From 489ed914f154e96069affe17911bae8aa378fabc Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 13 Oct 2025 11:28:17 +0100 Subject: [PATCH 01/17] Split SARIF post-processing steps from `uploadSpecifiedFiles` into a function --- lib/analyze-action.js | 50 ++++++++++------ lib/init-action-post.js | 50 ++++++++++------ lib/upload-lib.js | 52 ++++++++++------ lib/upload-sarif-action.js | 22 +++++-- src/upload-lib.ts | 119 +++++++++++++++++++++++++------------ 5 files changed, 192 insertions(+), 101 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 7069a7375..9531dc918 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -95898,26 +95898,11 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { - const sarifPaths = getSarifFilePaths( - inputSarifPath, - uploadTarget.sarifPredicate - ); - return uploadSpecifiedFiles( - sarifPaths, - checkoutPath, - category, - features, - logger, - uploadTarget - ); -} -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); +async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; - category = uploadTarget.fixCategory(logger, category); + category = analysis.fixCategory(logger, category); if (sarifPaths.length > 1) { for (const sarifPath of sarifPaths) { const parsedSarif = readSarifFile(sarifPath); @@ -95945,6 +95930,33 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features analysisKey, environment ); + return { sarif, analysisKey, environment }; +} +async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { + const sarifPaths = getSarifFilePaths( + inputSarifPath, + uploadTarget.sarifPredicate + ); + return uploadSpecifiedFiles( + sarifPaths, + checkoutPath, + category, + features, + logger, + uploadTarget + ); +} +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); + const processingResults = await postProcessSarifFiles( + logger, + features, + checkoutPath, + sarifPaths, + category, + uploadTarget + ); + const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -95960,13 +95972,13 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - analysisKey, + processingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - environment, + processingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index bb0b377d3..5bf4bb579 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -133309,26 +133309,11 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { - const sarifPaths = getSarifFilePaths( - inputSarifPath, - uploadTarget.sarifPredicate - ); - return uploadSpecifiedFiles( - sarifPaths, - checkoutPath, - category, - features, - logger, - uploadTarget - ); -} -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); +async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; - category = uploadTarget.fixCategory(logger, category); + category = analysis.fixCategory(logger, category); if (sarifPaths.length > 1) { for (const sarifPath of sarifPaths) { const parsedSarif = readSarifFile(sarifPath); @@ -133356,6 +133341,33 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features analysisKey, environment ); + return { sarif, analysisKey, environment }; +} +async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { + const sarifPaths = getSarifFilePaths( + inputSarifPath, + uploadTarget.sarifPredicate + ); + return uploadSpecifiedFiles( + sarifPaths, + checkoutPath, + category, + features, + logger, + uploadTarget + ); +} +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); + const processingResults = await postProcessSarifFiles( + logger, + features, + checkoutPath, + sarifPaths, + category, + uploadTarget + ); + const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -133371,13 +133383,13 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - analysisKey, + processingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - environment, + processingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); diff --git a/lib/upload-lib.js b/lib/upload-lib.js index 490fabfa8..8c7fa5434 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -84847,6 +84847,7 @@ __export(upload_lib_exports, { getGroupedSarifFilePaths: () => getGroupedSarifFilePaths, getSarifFilePaths: () => getSarifFilePaths, populateRunAutomationDetails: () => populateRunAutomationDetails, + postProcessSarifFiles: () => postProcessSarifFiles, readSarifFile: () => readSarifFile, shouldConsiderConfigurationError: () => shouldConsiderConfigurationError, shouldConsiderInvalidRequest: () => shouldConsiderInvalidRequest, @@ -92712,26 +92713,11 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { - const sarifPaths = getSarifFilePaths( - inputSarifPath, - uploadTarget.sarifPredicate - ); - return uploadSpecifiedFiles( - sarifPaths, - checkoutPath, - category, - features, - logger, - uploadTarget - ); -} -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); +async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; - category = uploadTarget.fixCategory(logger, category); + category = analysis.fixCategory(logger, category); if (sarifPaths.length > 1) { for (const sarifPath of sarifPaths) { const parsedSarif = readSarifFile(sarifPath); @@ -92759,6 +92745,33 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features analysisKey, environment ); + return { sarif, analysisKey, environment }; +} +async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { + const sarifPaths = getSarifFilePaths( + inputSarifPath, + uploadTarget.sarifPredicate + ); + return uploadSpecifiedFiles( + sarifPaths, + checkoutPath, + category, + features, + logger, + uploadTarget + ); +} +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); + const processingResults = await postProcessSarifFiles( + logger, + features, + checkoutPath, + sarifPaths, + category, + uploadTarget + ); + const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -92774,13 +92787,13 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - analysisKey, + processingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - environment, + processingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); @@ -92980,6 +92993,7 @@ function filterAlertsByDiffRange(logger, sarif) { getGroupedSarifFilePaths, getSarifFilePaths, populateRunAutomationDetails, + postProcessSarifFiles, readSarifFile, shouldConsiderConfigurationError, shouldConsiderInvalidRequest, diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 73391b6be..128721983 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93368,12 +93368,11 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); +async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; - category = uploadTarget.fixCategory(logger, category); + category = analysis.fixCategory(logger, category); if (sarifPaths.length > 1) { for (const sarifPath of sarifPaths) { const parsedSarif = readSarifFile(sarifPath); @@ -93401,6 +93400,19 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features analysisKey, environment ); + return { sarif, analysisKey, environment }; +} +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); + const processingResults = await postProcessSarifFiles( + logger, + features, + checkoutPath, + sarifPaths, + category, + uploadTarget + ); + const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -93416,13 +93428,13 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - analysisKey, + processingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - environment, + processingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); diff --git a/src/upload-lib.ts b/src/upload-lib.ts index b765cd397..0b553157e 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -688,6 +688,77 @@ export function buildPayload( return payloadObj; } +export interface PostProcessingResults { + sarif: util.SarifFile; + analysisKey: string; + environment: string; +} + +/** + * Performs post-processing of the SARIF files given by `sarifPaths`. + * + * @param logger The logger to use. + * @param features Information about enabled features. + * @param checkoutPath The path where the repo was checked out at. + * @param sarifPaths The paths of the SARIF files to post-process. + * @param category The analysis category. + * @param analysis The analysis configuration. + * + * @returns Returns the results of post-processing the SARIF files, + * including the resulting SARIF file. + */ +export async function postProcessSarifFiles( + logger: Logger, + features: FeatureEnablement, + checkoutPath: string, + sarifPaths: string[], + category: string | undefined, + analysis: analyses.AnalysisConfig, +): Promise { + logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); + + const gitHubVersion = await getGitHubVersion(); + + let sarif: SarifFile; + category = analysis.fixCategory(logger, category); + + if (sarifPaths.length > 1) { + // Validate that the files we were asked to upload are all valid SARIF files + for (const sarifPath of sarifPaths) { + const parsedSarif = readSarifFile(sarifPath); + validateSarifFileSchema(parsedSarif, sarifPath, logger); + } + + sarif = await combineSarifFilesUsingCLI( + sarifPaths, + gitHubVersion, + features, + logger, + ); + } else { + const sarifPath = sarifPaths[0]; + sarif = readSarifFile(sarifPath); + validateSarifFileSchema(sarif, sarifPath, logger); + + // Validate that there are no runs for the same category + await throwIfCombineSarifFilesDisabled([sarif], gitHubVersion); + } + + sarif = filterAlertsByDiffRange(logger, sarif); + sarif = await fingerprints.addFingerprints(sarif, checkoutPath, logger); + + const analysisKey = await api.getAnalysisKey(); + const environment = actionsUtil.getRequiredInput("matrix"); + sarif = populateRunAutomationDetails( + sarif, + category, + analysisKey, + environment, + ); + + return { sarif, analysisKey, environment }; +} + /** * Uploads a single SARIF file or a directory of SARIF files depending on what `inputSarifPath` refers * to. @@ -727,46 +798,16 @@ export async function uploadSpecifiedFiles( uploadTarget: analyses.AnalysisConfig, ): Promise { logger.startGroup(`Uploading ${uploadTarget.name} results`); - logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); - const gitHubVersion = await getGitHubVersion(); - - let sarif: SarifFile; - category = uploadTarget.fixCategory(logger, category); - - if (sarifPaths.length > 1) { - // Validate that the files we were asked to upload are all valid SARIF files - for (const sarifPath of sarifPaths) { - const parsedSarif = readSarifFile(sarifPath); - validateSarifFileSchema(parsedSarif, sarifPath, logger); - } - - sarif = await combineSarifFilesUsingCLI( - sarifPaths, - gitHubVersion, - features, - logger, - ); - } else { - const sarifPath = sarifPaths[0]; - sarif = readSarifFile(sarifPath); - validateSarifFileSchema(sarif, sarifPath, logger); - - // Validate that there are no runs for the same category - await throwIfCombineSarifFilesDisabled([sarif], gitHubVersion); - } - - sarif = filterAlertsByDiffRange(logger, sarif); - sarif = await fingerprints.addFingerprints(sarif, checkoutPath, logger); - - const analysisKey = await api.getAnalysisKey(); - const environment = actionsUtil.getRequiredInput("matrix"); - sarif = populateRunAutomationDetails( - sarif, + const processingResults: PostProcessingResults = await postProcessSarifFiles( + logger, + features, + checkoutPath, + sarifPaths, category, - analysisKey, - environment, + uploadTarget, ); + const sarif = processingResults.sarif; const toolNames = util.getToolNames(sarif); @@ -787,13 +828,13 @@ export async function uploadSpecifiedFiles( const payload = buildPayload( await gitUtils.getCommitOid(checkoutPath), await gitUtils.getRef(), - analysisKey, + processingResults.analysisKey, util.getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, actionsUtil.getWorkflowRunID(), actionsUtil.getWorkflowRunAttempt(), checkoutURI, - environment, + processingResults.environment, toolNames, await gitUtils.determineBaseBranchHeadCommitOid(), ); From 6fbdd5f4e99309683ecfa95bfee3fad77736d152 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 21 Oct 2025 23:17:01 +0100 Subject: [PATCH 02/17] Split SARIF uploading steps from `uploadSpecifiedFiles` into a function --- lib/analyze-action.js | 10 +++++++++- lib/init-action-post.js | 10 +++++++++- lib/upload-lib.js | 12 +++++++++++- lib/upload-sarif-action.js | 10 +++++++++- src/upload-lib.ts | 29 +++++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 9531dc918..3cb5f67d2 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -95947,7 +95947,6 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log ); } async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); const processingResults = await postProcessSarifFiles( logger, features, @@ -95956,6 +95955,15 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); + return uploadProcessedFiles( + logger, + checkoutPath, + uploadTarget, + processingResults + ); +} +async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 5bf4bb579..8992fedfe 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -133358,7 +133358,6 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log ); } async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); const processingResults = await postProcessSarifFiles( logger, features, @@ -133367,6 +133366,15 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); + return uploadProcessedFiles( + logger, + checkoutPath, + uploadTarget, + processingResults + ); +} +async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); diff --git a/lib/upload-lib.js b/lib/upload-lib.js index 8c7fa5434..b7da39a6a 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -84855,6 +84855,7 @@ __export(upload_lib_exports, { throwIfCombineSarifFilesDisabled: () => throwIfCombineSarifFilesDisabled, uploadFiles: () => uploadFiles, uploadPayload: () => uploadPayload, + uploadProcessedFiles: () => uploadProcessedFiles, uploadSpecifiedFiles: () => uploadSpecifiedFiles, validateSarifFileSchema: () => validateSarifFileSchema, validateUniqueCategory: () => validateUniqueCategory, @@ -92762,7 +92763,6 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log ); } async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); const processingResults = await postProcessSarifFiles( logger, features, @@ -92771,6 +92771,15 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); + return uploadProcessedFiles( + logger, + checkoutPath, + uploadTarget, + processingResults + ); +} +async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); @@ -93001,6 +93010,7 @@ function filterAlertsByDiffRange(logger, sarif) { throwIfCombineSarifFilesDisabled, uploadFiles, uploadPayload, + uploadProcessedFiles, uploadSpecifiedFiles, validateSarifFileSchema, validateUniqueCategory, diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 128721983..121fd5a3e 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93403,7 +93403,6 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, return { sarif, analysisKey, environment }; } async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - logger.startGroup(`Uploading ${uploadTarget.name} results`); const processingResults = await postProcessSarifFiles( logger, features, @@ -93412,6 +93411,15 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); + return uploadProcessedFiles( + logger, + checkoutPath, + uploadTarget, + processingResults + ); +} +async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { + logger.startGroup(`Uploading ${uploadTarget.name} results`); const sarif = processingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 0b553157e..9febcb8d0 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -797,8 +797,6 @@ export async function uploadSpecifiedFiles( logger: Logger, uploadTarget: analyses.AnalysisConfig, ): Promise { - logger.startGroup(`Uploading ${uploadTarget.name} results`); - const processingResults: PostProcessingResults = await postProcessSarifFiles( logger, features, @@ -807,6 +805,33 @@ export async function uploadSpecifiedFiles( category, uploadTarget, ); + + return uploadProcessedFiles( + logger, + checkoutPath, + uploadTarget, + processingResults, + ); +} + +/** + * Uploads the + * + * @param logger The logger to use. + * @param checkoutPath The path at which the repository was checked out. + * @param uploadTarget The analysis configuration. + * @param processingResults The results of post-processing SARIF files. + * + * @returns The results of uploading the `processingResults` to `uploadTarget`. + */ +export async function uploadProcessedFiles( + logger: Logger, + checkoutPath: string, + uploadTarget: analyses.AnalysisConfig, + processingResults: PostProcessingResults, +): Promise { + logger.startGroup(`Uploading ${uploadTarget.name} results`); + const sarif = processingResults.sarif; const toolNames = util.getToolNames(sarif); From 899bf2fd1e2a8cdc62e04f8c35ae6c710522f072 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 21 Oct 2025 23:32:51 +0100 Subject: [PATCH 03/17] Use `postProcessSarifFiles` and `uploadProcessedFiles` in `uploadSarif` --- lib/analyze-action.js | 16 +++++++++---- lib/upload-lib.js | 2 -- lib/upload-sarif-action.js | 32 +++++++++---------------- src/upload-lib.ts | 2 +- src/upload-sarif.test.ts | 48 +++++++++++++++++++++----------------- src/upload-sarif.ts | 17 ++++++++++---- 6 files changed, 62 insertions(+), 55 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 3cb5f67d2..a43be6256 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -96190,14 +96190,20 @@ async function uploadSarif(logger, features, checkoutPath, sarifPath, category) sarifGroups )) { const analysisConfig = getAnalysisConfig(analysisKind); - uploadResults[analysisKind] = await uploadSpecifiedFiles( - sarifFiles, - checkoutPath, - category, - features, + const processingResults = await postProcessSarifFiles( logger, + features, + checkoutPath, + sarifFiles, + category, analysisConfig ); + uploadResults[analysisKind] = await uploadProcessedFiles( + logger, + checkoutPath, + analysisConfig, + processingResults + ); } return uploadResults; } diff --git a/lib/upload-lib.js b/lib/upload-lib.js index b7da39a6a..15ddf8da2 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -84856,7 +84856,6 @@ __export(upload_lib_exports, { uploadFiles: () => uploadFiles, uploadPayload: () => uploadPayload, uploadProcessedFiles: () => uploadProcessedFiles, - uploadSpecifiedFiles: () => uploadSpecifiedFiles, validateSarifFileSchema: () => validateSarifFileSchema, validateUniqueCategory: () => validateUniqueCategory, waitForProcessing: () => waitForProcessing @@ -93011,7 +93010,6 @@ function filterAlertsByDiffRange(logger, sarif) { uploadFiles, uploadPayload, uploadProcessedFiles, - uploadSpecifiedFiles, validateSarifFileSchema, validateUniqueCategory, waitForProcessing diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 121fd5a3e..a23b7d469 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93402,22 +93402,6 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { - const processingResults = await postProcessSarifFiles( - logger, - features, - checkoutPath, - sarifPaths, - category, - uploadTarget - ); - return uploadProcessedFiles( - logger, - checkoutPath, - uploadTarget, - processingResults - ); -} async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { logger.startGroup(`Uploading ${uploadTarget.name} results`); const sarif = processingResults.sarif; @@ -93646,14 +93630,20 @@ async function uploadSarif(logger, features, checkoutPath, sarifPath, category) sarifGroups )) { const analysisConfig = getAnalysisConfig(analysisKind); - uploadResults[analysisKind] = await uploadSpecifiedFiles( - sarifFiles, - checkoutPath, - category, - features, + const processingResults = await postProcessSarifFiles( logger, + features, + checkoutPath, + sarifFiles, + category, analysisConfig ); + uploadResults[analysisKind] = await uploadProcessedFiles( + logger, + checkoutPath, + analysisConfig, + processingResults + ); } return uploadResults; } diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 9febcb8d0..0dcadffe5 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -789,7 +789,7 @@ export async function uploadFiles( /** * Uploads the given array of SARIF files. */ -export async function uploadSpecifiedFiles( +async function uploadSpecifiedFiles( sarifPaths: string[], checkoutPath: string, category: string | undefined, diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index 893330eda..e932b65ff 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -33,21 +33,29 @@ const uploadSarifMacro = test.macro({ const toFullPath = (filename: string) => path.join(tempDir, filename); - const uploadSpecifiedFiles = sinon.stub( + const postProcessSarifFiles = sinon.stub( uploadLib, - "uploadSpecifiedFiles", + "postProcessSarifFiles", + ); + const uploadProcessedFiles = sinon.stub( + uploadLib, + "uploadProcessedFiles", ); for (const analysisKind of Object.values(AnalysisKind)) { - uploadSpecifiedFiles + const analysisConfig = getAnalysisConfig(analysisKind); + postProcessSarifFiles .withArgs( - sinon.match.any, - sinon.match.any, - sinon.match.any, - features, logger, - getAnalysisConfig(analysisKind), + sinon.match.any, + sinon.match.any, + sinon.match.any, + sinon.match.any, + analysisConfig, ) + .resolves({ sarif: { runs: [] }, analysisKey: "", environment: "" }); + uploadProcessedFiles + .withArgs(logger, sinon.match.any, analysisConfig, sinon.match.any) .resolves(expectedResult[analysisKind as AnalysisKind]?.uploadResult); } @@ -63,35 +71,33 @@ const uploadSarifMacro = test.macro({ if (analysisKindResult) { // We are expecting a result for this analysis kind, check that we have it. t.deepEqual(actual[analysisKind], analysisKindResult.uploadResult); - // Additionally, check that the mocked `uploadSpecifiedFiles` was called with only the file paths + // Additionally, check that the mocked `postProcessSarifFiles` was called with only the file paths // that we expected it to be called with. t.assert( - uploadSpecifiedFiles.calledWith( + postProcessSarifFiles.calledWith( + logger, + features, + sinon.match.any, analysisKindResult.expectedFiles?.map(toFullPath) ?? fullSarifPaths, sinon.match.any, - sinon.match.any, - features, - logger, getAnalysisConfig(analysisKind), ), ); } else { // Otherwise, we are not expecting a result for this analysis kind. However, note that `undefined` - // is also returned by our mocked `uploadSpecifiedFiles` when there is no expected result for this + // is also returned by our mocked `uploadProcessedFiles` when there is no expected result for this // analysis kind. t.is(actual[analysisKind], undefined); - // Therefore, we also check that the mocked `uploadSpecifiedFiles` was not called for this analysis kind. + // Therefore, we also check that the mocked `uploadProcessedFiles` was not called for this analysis kind. t.assert( - !uploadSpecifiedFiles.calledWith( - sinon.match.any, - sinon.match.any, - sinon.match.any, - features, + !uploadProcessedFiles.calledWith( logger, + sinon.match.any, getAnalysisConfig(analysisKind), + sinon.match.any, ), - `uploadSpecifiedFiles was called for ${analysisKind}, but should not have been.`, + `uploadProcessedFiles was called for ${analysisKind}, but should not have been.`, ); } } diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index 34b912489..df3461643 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -37,14 +37,21 @@ export async function uploadSarif( sarifGroups, )) { const analysisConfig = analyses.getAnalysisConfig(analysisKind); - uploadResults[analysisKind] = await upload_lib.uploadSpecifiedFiles( - sarifFiles, - checkoutPath, - category, - features, + const processingResults = await upload_lib.postProcessSarifFiles( logger, + features, + checkoutPath, + sarifFiles, + category, analysisConfig, ); + + uploadResults[analysisKind] = await upload_lib.uploadProcessedFiles( + logger, + checkoutPath, + analysisConfig, + processingResults, + ); } return uploadResults; From 596de7f1bc1027a9856c6855d3b8ef29fd4820c7 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 21 Oct 2025 23:41:40 +0100 Subject: [PATCH 04/17] Move `UploadKind` check into `uploadSarif` --- lib/analyze-action.js | 23 ++++++++++++++--------- lib/upload-sarif-action.js | 17 ++++++++++------- src/analyze-action.ts | 7 +++++-- src/upload-sarif-action.ts | 1 + src/upload-sarif.test.ts | 8 +++++++- src/upload-sarif.ts | 18 ++++++++++++------ 6 files changed, 49 insertions(+), 25 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index a43be6256..887d7e3bf 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -96180,7 +96180,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function uploadSarif(logger, features, checkoutPath, sarifPath, category) { +async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -96198,12 +96198,14 @@ async function uploadSarif(logger, features, checkoutPath, sarifPath, category) category, analysisConfig ); - uploadResults[analysisKind] = await uploadProcessedFiles( - logger, - checkoutPath, - analysisConfig, - processingResults - ); + if (uploadKind === "always") { + uploadResults[analysisKind] = await uploadProcessedFiles( + logger, + checkoutPath, + analysisConfig, + processingResults + ); + } } return uploadResults; } @@ -96402,14 +96404,17 @@ async function run() { } core14.setOutput("db-locations", dbLocations); core14.setOutput("sarif-output", import_path4.default.resolve(outputDir)); - const uploadInput = getOptionalInput("upload"); - if (runStats && getUploadValue(uploadInput) === "always") { + const uploadKind = getUploadValue( + getOptionalInput("upload") + ); + if (runStats) { const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); if (await features.getValue("analyze_use_new_upload" /* AnalyzeUseNewUpload */)) { uploadResults = await uploadSarif( logger, features, + uploadKind, checkoutPath, outputDir, category diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index a23b7d469..547ef8f10 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93620,7 +93620,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function uploadSarif(logger, features, checkoutPath, sarifPath, category) { +async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -93638,12 +93638,14 @@ async function uploadSarif(logger, features, checkoutPath, sarifPath, category) category, analysisConfig ); - uploadResults[analysisKind] = await uploadProcessedFiles( - logger, - checkoutPath, - analysisConfig, - processingResults - ); + if (uploadKind === "always") { + uploadResults[analysisKind] = await uploadProcessedFiles( + logger, + checkoutPath, + analysisConfig, + processingResults + ); + } } return uploadResults; } @@ -93698,6 +93700,7 @@ async function run() { const uploadResults = await uploadSarif( logger, features, + "always", checkoutPath, sarifPath, category diff --git a/src/analyze-action.ts b/src/analyze-action.ts index b6aa05ebe..36517624d 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -344,8 +344,10 @@ async function run() { } core.setOutput("db-locations", dbLocations); core.setOutput("sarif-output", path.resolve(outputDir)); - const uploadInput = actionsUtil.getOptionalInput("upload"); - if (runStats && actionsUtil.getUploadValue(uploadInput) === "always") { + const uploadKind = actionsUtil.getUploadValue( + actionsUtil.getOptionalInput("upload"), + ); + if (runStats) { const checkoutPath = actionsUtil.getRequiredInput("checkout_path"); const category = actionsUtil.getOptionalInput("category"); @@ -353,6 +355,7 @@ async function run() { uploadResults = await uploadSarif( logger, features, + uploadKind, checkoutPath, outputDir, category, diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index a2ef43eb4..8a8bca8b7 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -93,6 +93,7 @@ async function run() { const uploadResults = await uploadSarif( logger, features, + "always", checkoutPath, sarifPath, category, diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index e932b65ff..f3305c92a 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -64,7 +64,13 @@ const uploadSarifMacro = test.macro({ fs.writeFileSync(sarifFile, ""); } - const actual = await uploadSarif(logger, features, "", testPath); + const actual = await uploadSarif( + logger, + features, + "always", + "", + testPath, + ); for (const analysisKind of Object.values(AnalysisKind)) { const analysisKindResult = expectedResult[analysisKind]; diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index df3461643..7fc2d2cd3 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -1,3 +1,4 @@ +import { UploadKind } from "./actions-util"; import * as analyses from "./analyses"; import { FeatureEnablement } from "./feature-flags"; import { Logger } from "./logging"; @@ -14,6 +15,7 @@ export type UploadSarifResults = Partial< * * @param logger The logger to use. * @param features Information about enabled features. + * @param uploadKind The kind of upload that is requested. * @param checkoutPath The path where the repository was checked out at. * @param sarifPath The path to the file or directory to upload. * @param category The analysis category. @@ -23,6 +25,7 @@ export type UploadSarifResults = Partial< export async function uploadSarif( logger: Logger, features: FeatureEnablement, + uploadKind: UploadKind, checkoutPath: string, sarifPath: string, category?: string, @@ -46,12 +49,15 @@ export async function uploadSarif( analysisConfig, ); - uploadResults[analysisKind] = await upload_lib.uploadProcessedFiles( - logger, - checkoutPath, - analysisConfig, - processingResults, - ); + // Only perform the actual upload of the processed files, if `uploadKind` is `always`. + if (uploadKind === "always") { + uploadResults[analysisKind] = await upload_lib.uploadProcessedFiles( + logger, + checkoutPath, + analysisConfig, + processingResults, + ); + } } return uploadResults; From 14139c9f7766ce3519131b717ad9df0ba9d9254f Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 21 Oct 2025 23:49:29 +0100 Subject: [PATCH 05/17] Add test for `uploadSarif` with `upload: never` --- src/upload-sarif.test.ts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index f3305c92a..f8ac0d26b 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -195,3 +195,41 @@ test( }, }, ); + +test("uploadSarif doesn't upload if `upload` != `always`", async (t) => { + await util.withTmpDir(async (tempDir) => { + const logger = getRunnerLogger(true); + const features = createFeatures([]); + + const toFullPath = (filename: string) => path.join(tempDir, filename); + + const postProcessSarifFiles = sinon.stub( + uploadLib, + "postProcessSarifFiles", + ); + const uploadProcessedFiles = sinon.stub(uploadLib, "uploadProcessedFiles"); + + for (const analysisKind of Object.values(AnalysisKind)) { + const analysisConfig = getAnalysisConfig(analysisKind); + postProcessSarifFiles + .withArgs( + logger, + sinon.match.any, + sinon.match.any, + sinon.match.any, + sinon.match.any, + analysisConfig, + ) + .resolves({ sarif: { runs: [] }, analysisKey: "", environment: "" }); + } + + fs.writeFileSync(toFullPath("test.sarif"), ""); + fs.writeFileSync(toFullPath("test.quality.sarif"), ""); + + const actual = await uploadSarif(logger, features, "never", "", tempDir); + + t.truthy(actual); + t.assert(postProcessSarifFiles.calledTwice); + t.assert(uploadProcessedFiles.notCalled); + }); +}); From c2bec36917d1974b9f0efdc8d1047453900f6a0a Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 21 Oct 2025 23:56:44 +0100 Subject: [PATCH 06/17] Add `post-process-output` input to `analyze` action --- analyze/action.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/analyze/action.yml b/analyze/action.yml index 7fc118b15..438406761 100644 --- a/analyze/action.yml +++ b/analyze/action.yml @@ -6,7 +6,7 @@ inputs: description: The name of the check run to add text to. required: false output: - description: The path of the directory in which to save the SARIF results + description: The path of the directory in which to save the SARIF results from the CodeQL CLI. required: false default: "../results" upload: @@ -70,6 +70,12 @@ inputs: description: Whether to upload the resulting CodeQL database required: false default: "true" + post-process-output: + description: >- + Before uploading the SARIF files produced by the CodeQL CLI, the CodeQL Action may perform some post-processing + on them. Ordinarily, these processed SARIF files are not saved to disk. However, if a path is provided as an + argument for this input, they are written to the specified directory. + required: false wait-for-processing: description: If true, the Action will wait for the uploaded SARIF to be processed before completing. required: true From 12f3cfef092149eeb578ebc6fe6aa2f203884505 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 00:16:27 +0100 Subject: [PATCH 07/17] Write processed SARIF files if `post-process-output` input is provided --- lib/analyze-action.js | 32 +++++++++++++++++++++++-------- lib/init-action-post.js | 19 ------------------- lib/upload-lib.js | 27 ++++++++++++++++++-------- lib/upload-sarif-action.js | 29 +++++++++++++++++++++------- src/analyze-action.ts | 1 + src/upload-lib.ts | 39 +++++++++++++++++++++++++++++++------- src/upload-sarif.ts | 11 +++++++++++ 7 files changed, 109 insertions(+), 49 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 887d7e3bf..d422ad609 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -95932,6 +95932,19 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } +async function writeProcessedFiles(logger, pathInput, uploadTarget, processingResults) { + const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; + if (outputPath !== void 0) { + dumpSarifFile( + JSON.stringify(processingResults.sarif), + outputPath, + logger, + uploadTarget + ); + } else { + logger.debug(`Not writing processed SARIF files.`); + } +} async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -95970,10 +95983,6 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); logger.debug(`Serializing SARIF for upload`); const sarifPayload = JSON.stringify(sarif); - const dumpDir = process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (dumpDir) { - dumpSarifFile(sarifPayload, dumpDir, logger, uploadTarget); - } logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; @@ -96017,14 +96026,14 @@ function dumpSarifFile(sarifPayload, outputDir, logger, uploadTarget) { fs18.mkdirSync(outputDir, { recursive: true }); } else if (!fs18.lstatSync(outputDir).isDirectory()) { throw new ConfigurationError( - `The path specified by the ${"CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */} environment variable exists and is not a directory: ${outputDir}` + `The path that processed SARIF files should be written to exists, but is not a directory: ${outputDir}` ); } const outputFile = path18.resolve( outputDir, `upload${uploadTarget.sarifExtension}` ); - logger.info(`Dumping processed SARIF file to ${outputFile}`); + logger.info(`Writing processed SARIF file to ${outputFile}`); fs18.writeFileSync(outputFile, sarifPayload); } var STATUS_CHECK_FREQUENCY_MILLISECONDS = 5 * 1e3; @@ -96180,7 +96189,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category) { +async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -96198,6 +96207,12 @@ async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath category, analysisConfig ); + await writeProcessedFiles( + logger, + processedOutputPath, + analysisConfig, + processingResults + ); if (uploadKind === "always") { uploadResults[analysisKind] = await uploadProcessedFiles( logger, @@ -96417,7 +96432,8 @@ async function run() { uploadKind, checkoutPath, outputDir, - category + category, + getOptionalInput("post-process-output") ); } else { uploadResults = {}; diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 8992fedfe..4cf9954e9 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -133381,10 +133381,6 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); logger.debug(`Serializing SARIF for upload`); const sarifPayload = JSON.stringify(sarif); - const dumpDir = process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (dumpDir) { - dumpSarifFile(sarifPayload, dumpDir, logger, uploadTarget); - } logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; @@ -133423,21 +133419,6 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi sarifID }; } -function dumpSarifFile(sarifPayload, outputDir, logger, uploadTarget) { - if (!fs17.existsSync(outputDir)) { - fs17.mkdirSync(outputDir, { recursive: true }); - } else if (!fs17.lstatSync(outputDir).isDirectory()) { - throw new ConfigurationError( - `The path specified by the ${"CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */} environment variable exists and is not a directory: ${outputDir}` - ); - } - const outputFile = path17.resolve( - outputDir, - `upload${uploadTarget.sarifExtension}` - ); - logger.info(`Dumping processed SARIF file to ${outputFile}`); - fs17.writeFileSync(outputFile, sarifPayload); -} var STATUS_CHECK_FREQUENCY_MILLISECONDS = 5 * 1e3; var STATUS_CHECK_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3; async function waitForProcessing(repositoryNwo, sarifID, logger, options = { diff --git a/lib/upload-lib.js b/lib/upload-lib.js index 15ddf8da2..ee0ae0d53 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -84858,7 +84858,8 @@ __export(upload_lib_exports, { uploadProcessedFiles: () => uploadProcessedFiles, validateSarifFileSchema: () => validateSarifFileSchema, validateUniqueCategory: () => validateUniqueCategory, - waitForProcessing: () => waitForProcessing + waitForProcessing: () => waitForProcessing, + writeProcessedFiles: () => writeProcessedFiles }); module.exports = __toCommonJS(upload_lib_exports); var fs13 = __toESM(require("fs")); @@ -92747,6 +92748,19 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } +async function writeProcessedFiles(logger, pathInput, uploadTarget, processingResults) { + const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; + if (outputPath !== void 0) { + dumpSarifFile( + JSON.stringify(processingResults.sarif), + outputPath, + logger, + uploadTarget + ); + } else { + logger.debug(`Not writing processed SARIF files.`); + } +} async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -92785,10 +92799,6 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); logger.debug(`Serializing SARIF for upload`); const sarifPayload = JSON.stringify(sarif); - const dumpDir = process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (dumpDir) { - dumpSarifFile(sarifPayload, dumpDir, logger, uploadTarget); - } logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; @@ -92832,14 +92842,14 @@ function dumpSarifFile(sarifPayload, outputDir, logger, uploadTarget) { fs13.mkdirSync(outputDir, { recursive: true }); } else if (!fs13.lstatSync(outputDir).isDirectory()) { throw new ConfigurationError( - `The path specified by the ${"CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */} environment variable exists and is not a directory: ${outputDir}` + `The path that processed SARIF files should be written to exists, but is not a directory: ${outputDir}` ); } const outputFile = path14.resolve( outputDir, `upload${uploadTarget.sarifExtension}` ); - logger.info(`Dumping processed SARIF file to ${outputFile}`); + logger.info(`Writing processed SARIF file to ${outputFile}`); fs13.writeFileSync(outputFile, sarifPayload); } var STATUS_CHECK_FREQUENCY_MILLISECONDS = 5 * 1e3; @@ -93012,7 +93022,8 @@ function filterAlertsByDiffRange(logger, sarif) { uploadProcessedFiles, validateSarifFileSchema, validateUniqueCategory, - waitForProcessing + waitForProcessing, + writeProcessedFiles }); /*! Bundled license information: diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 547ef8f10..f7923ea81 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93402,6 +93402,19 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } +async function writeProcessedFiles(logger, pathInput, uploadTarget, processingResults) { + const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; + if (outputPath !== void 0) { + dumpSarifFile( + JSON.stringify(processingResults.sarif), + outputPath, + logger, + uploadTarget + ); + } else { + logger.debug(`Not writing processed SARIF files.`); + } +} async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { logger.startGroup(`Uploading ${uploadTarget.name} results`); const sarif = processingResults.sarif; @@ -93410,10 +93423,6 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); logger.debug(`Serializing SARIF for upload`); const sarifPayload = JSON.stringify(sarif); - const dumpDir = process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (dumpDir) { - dumpSarifFile(sarifPayload, dumpDir, logger, uploadTarget); - } logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; @@ -93457,14 +93466,14 @@ function dumpSarifFile(sarifPayload, outputDir, logger, uploadTarget) { fs14.mkdirSync(outputDir, { recursive: true }); } else if (!fs14.lstatSync(outputDir).isDirectory()) { throw new ConfigurationError( - `The path specified by the ${"CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */} environment variable exists and is not a directory: ${outputDir}` + `The path that processed SARIF files should be written to exists, but is not a directory: ${outputDir}` ); } const outputFile = path15.resolve( outputDir, `upload${uploadTarget.sarifExtension}` ); - logger.info(`Dumping processed SARIF file to ${outputFile}`); + logger.info(`Writing processed SARIF file to ${outputFile}`); fs14.writeFileSync(outputFile, sarifPayload); } var STATUS_CHECK_FREQUENCY_MILLISECONDS = 5 * 1e3; @@ -93620,7 +93629,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category) { +async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -93638,6 +93647,12 @@ async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath category, analysisConfig ); + await writeProcessedFiles( + logger, + processedOutputPath, + analysisConfig, + processingResults + ); if (uploadKind === "always") { uploadResults[analysisKind] = await uploadProcessedFiles( logger, diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 36517624d..fb510a727 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -359,6 +359,7 @@ async function run() { checkoutPath, outputDir, category, + actionsUtil.getOptionalInput("post-process-output"), ); } else { uploadResults = {}; diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 0dcadffe5..f69a05696 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -759,6 +759,36 @@ export async function postProcessSarifFiles( return { sarif, analysisKey, environment }; } +/** + * Writes the processed SARIF file to disk, if needed based on `pathInput` or the `SARIF_DUMP_DIR`. + * + * @param logger The logger to use. + * @param pathInput The input provided for `post-process-output`. + * @param uploadTarget The upload target. + * @param processingResults The results of post-processing SARIF files. + */ +export async function writeProcessedFiles( + logger: Logger, + pathInput: string | undefined, + uploadTarget: analyses.AnalysisConfig, + processingResults: PostProcessingResults, +) { + // If there's an explicit input, use that. Otherwise, use the value from the environment variable. + const outputPath = pathInput || process.env[EnvVar.SARIF_DUMP_DIR]; + + // If we have an output path, write the SARIF file to it. + if (outputPath !== undefined) { + dumpSarifFile( + JSON.stringify(processingResults.sarif), + outputPath, + logger, + uploadTarget, + ); + } else { + logger.debug(`Not writing processed SARIF files.`); + } +} + /** * Uploads a single SARIF file or a directory of SARIF files depending on what `inputSarifPath` refers * to. @@ -841,11 +871,6 @@ export async function uploadProcessedFiles( logger.debug(`Serializing SARIF for upload`); const sarifPayload = JSON.stringify(sarif); - const dumpDir = process.env[EnvVar.SARIF_DUMP_DIR]; - if (dumpDir) { - dumpSarifFile(sarifPayload, dumpDir, logger, uploadTarget); - } - logger.debug(`Compressing serialized SARIF`); const zippedSarif = zlib.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; @@ -905,14 +930,14 @@ function dumpSarifFile( fs.mkdirSync(outputDir, { recursive: true }); } else if (!fs.lstatSync(outputDir).isDirectory()) { throw new ConfigurationError( - `The path specified by the ${EnvVar.SARIF_DUMP_DIR} environment variable exists and is not a directory: ${outputDir}`, + `The path that processed SARIF files should be written to exists, but is not a directory: ${outputDir}`, ); } const outputFile = path.resolve( outputDir, `upload${uploadTarget.sarifExtension}`, ); - logger.info(`Dumping processed SARIF file to ${outputFile}`); + logger.info(`Writing processed SARIF file to ${outputFile}`); fs.writeFileSync(outputFile, sarifPayload); } diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index 7fc2d2cd3..87990089e 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -19,6 +19,7 @@ export type UploadSarifResults = Partial< * @param checkoutPath The path where the repository was checked out at. * @param sarifPath The path to the file or directory to upload. * @param category The analysis category. + * @param processedOutputPath The path to a directory to which the post-processed SARIF files should be written to. * * @returns A partial mapping from analysis kinds to the upload results. */ @@ -29,6 +30,7 @@ export async function uploadSarif( checkoutPath: string, sarifPath: string, category?: string, + processedOutputPath?: string, ): Promise { const sarifGroups = await upload_lib.getGroupedSarifFilePaths( logger, @@ -49,6 +51,15 @@ export async function uploadSarif( analysisConfig, ); + // Write the processed SARIF files to disk. This will only write them if needed based on user inputs + // or environment variables. + await upload_lib.writeProcessedFiles( + logger, + processedOutputPath, + analysisConfig, + processingResults, + ); + // Only perform the actual upload of the processed files, if `uploadKind` is `always`. if (uploadKind === "always") { uploadResults[analysisKind] = await upload_lib.uploadProcessedFiles( From def04c1c0ec9589b3a2943faa40a555c80a7a1a7 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 00:30:49 +0100 Subject: [PATCH 08/17] Add test for `uploadSarif` with output directory --- src/upload-sarif.test.ts | 86 +++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index f8ac0d26b..6acaff28f 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -19,6 +19,26 @@ interface UploadSarifExpectedResult { expectedFiles?: string[]; } +function mockPostProcessSarifFiles() { + const postProcessSarifFiles = sinon.stub(uploadLib, "postProcessSarifFiles"); + + for (const analysisKind of Object.values(AnalysisKind)) { + const analysisConfig = getAnalysisConfig(analysisKind); + postProcessSarifFiles + .withArgs( + sinon.match.any, + sinon.match.any, + sinon.match.any, + sinon.match.any, + sinon.match.any, + analysisConfig, + ) + .resolves({ sarif: { runs: [] }, analysisKey: "", environment: "" }); + } + + return postProcessSarifFiles; +} + const uploadSarifMacro = test.macro({ exec: async ( t: ExecutionContext, @@ -33,10 +53,7 @@ const uploadSarifMacro = test.macro({ const toFullPath = (filename: string) => path.join(tempDir, filename); - const postProcessSarifFiles = sinon.stub( - uploadLib, - "postProcessSarifFiles", - ); + const postProcessSarifFiles = mockPostProcessSarifFiles(); const uploadProcessedFiles = sinon.stub( uploadLib, "uploadProcessedFiles", @@ -44,16 +61,6 @@ const uploadSarifMacro = test.macro({ for (const analysisKind of Object.values(AnalysisKind)) { const analysisConfig = getAnalysisConfig(analysisKind); - postProcessSarifFiles - .withArgs( - logger, - sinon.match.any, - sinon.match.any, - sinon.match.any, - sinon.match.any, - analysisConfig, - ) - .resolves({ sarif: { runs: [] }, analysisKey: "", environment: "" }); uploadProcessedFiles .withArgs(logger, sinon.match.any, analysisConfig, sinon.match.any) .resolves(expectedResult[analysisKind as AnalysisKind]?.uploadResult); @@ -203,26 +210,9 @@ test("uploadSarif doesn't upload if `upload` != `always`", async (t) => { const toFullPath = (filename: string) => path.join(tempDir, filename); - const postProcessSarifFiles = sinon.stub( - uploadLib, - "postProcessSarifFiles", - ); + const postProcessSarifFiles = mockPostProcessSarifFiles(); const uploadProcessedFiles = sinon.stub(uploadLib, "uploadProcessedFiles"); - for (const analysisKind of Object.values(AnalysisKind)) { - const analysisConfig = getAnalysisConfig(analysisKind); - postProcessSarifFiles - .withArgs( - logger, - sinon.match.any, - sinon.match.any, - sinon.match.any, - sinon.match.any, - analysisConfig, - ) - .resolves({ sarif: { runs: [] }, analysisKey: "", environment: "" }); - } - fs.writeFileSync(toFullPath("test.sarif"), ""); fs.writeFileSync(toFullPath("test.quality.sarif"), ""); @@ -233,3 +223,35 @@ test("uploadSarif doesn't upload if `upload` != `always`", async (t) => { t.assert(uploadProcessedFiles.notCalled); }); }); + +test("uploadSarif writes processed SARIF files if output directory is provided", async (t) => { + await util.withTmpDir(async (tempDir) => { + const logger = getRunnerLogger(true); + const features = createFeatures([]); + + const toFullPath = (filename: string) => path.join(tempDir, filename); + + const postProcessSarifFiles = mockPostProcessSarifFiles(); + + fs.writeFileSync(toFullPath("test.sarif"), ""); + fs.writeFileSync(toFullPath("test.quality.sarif"), ""); + + const processedOutPath = path.join(tempDir, "processed"); + const actual = await uploadSarif( + logger, + features, + "never", + "", + tempDir, + "", + processedOutPath, + ); + + t.truthy(actual); + t.assert(postProcessSarifFiles.calledTwice); + t.assert(fs.existsSync(path.join(processedOutPath, "upload.sarif"))); + t.assert( + fs.existsSync(path.join(processedOutPath, "upload.quality.sarif")), + ); + }); +}); From 5e37670026ac622fd0320cc3943d1d101d1e5a65 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 01:14:26 +0100 Subject: [PATCH 09/17] Use `post-process-output` in PR check --- .github/workflows/__quality-queries.yml | 9 +++++++++ pr-checks/checks/quality-queries.yml | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/__quality-queries.yml b/.github/workflows/__quality-queries.yml index c4aa5ffaf..d75f1520f 100644 --- a/.github/workflows/__quality-queries.yml +++ b/.github/workflows/__quality-queries.yml @@ -80,6 +80,7 @@ jobs: with: output: ${{ runner.temp }}/results upload-database: false + post-process-output: ${{ runner.temp }}/processed - name: Upload security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 @@ -96,6 +97,14 @@ jobs: quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json path: ${{ runner.temp }}/results/javascript.quality.sarif retention-days: 7 + - name: Upload processed SARIF + uses: actions/upload-artifact@v4 + with: + name: | + processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json + path: ${{ runner.temp }}/processed + retention-days: 7 + if-no-files-found: error - name: Check quality query does not appear in security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/github-script@v8 diff --git a/pr-checks/checks/quality-queries.yml b/pr-checks/checks/quality-queries.yml index b8420ad20..2304daacb 100644 --- a/pr-checks/checks/quality-queries.yml +++ b/pr-checks/checks/quality-queries.yml @@ -36,6 +36,7 @@ steps: with: output: "${{ runner.temp }}/results" upload-database: false + post-process-output: "${{ runner.temp }}/processed" - name: Upload security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 @@ -52,6 +53,14 @@ steps: quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json path: "${{ runner.temp }}/results/javascript.quality.sarif" retention-days: 7 + - name: Upload processed SARIF + uses: actions/upload-artifact@v4 + with: + name: | + processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json + path: "${{ runner.temp }}/processed" + retention-days: 7 + if-no-files-found: error - name: Check quality query does not appear in security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/github-script@v8 From d79c0a133909f49f2c15c1a46b1462d18ef775f1 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 19:03:23 +0100 Subject: [PATCH 10/17] Fix incomplete comment --- src/upload-lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upload-lib.ts b/src/upload-lib.ts index f69a05696..db2bafd11 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -845,7 +845,7 @@ async function uploadSpecifiedFiles( } /** - * Uploads the + * Uploads the results of processing SARIF files to the specified upload target. * * @param logger The logger to use. * @param checkoutPath The path at which the repository was checked out. From 89d33590177af96a27f710c2772a5a479bce8b7c Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 19:05:05 +0100 Subject: [PATCH 11/17] Improve test name --- src/upload-sarif.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index 6acaff28f..cce178060 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -203,7 +203,7 @@ test( }, ); -test("uploadSarif doesn't upload if `upload` != `always`", async (t) => { +test("uploadSarif doesn't upload if upload is disabled", async (t) => { await util.withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const features = createFeatures([]); From 6f0fcbeea7bcf5fa25efa506a9eda9d1ee938488 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 19:09:39 +0100 Subject: [PATCH 12/17] Rename `uploadSarif` --- lib/analyze-action.js | 4 ++-- lib/upload-sarif-action.js | 4 ++-- src/analyze-action.ts | 4 ++-- src/upload-sarif-action.ts | 4 ++-- src/upload-sarif.test.ts | 26 +++++++++++++------------- src/upload-sarif.ts | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index d422ad609..c5b340b28 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -96189,7 +96189,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { +async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -96426,7 +96426,7 @@ async function run() { const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); if (await features.getValue("analyze_use_new_upload" /* AnalyzeUseNewUpload */)) { - uploadResults = await uploadSarif( + uploadResults = await processAndUploadSarif( logger, features, uploadKind, diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index f7923ea81..300a18b5e 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93629,7 +93629,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function uploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { +async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -93712,7 +93712,7 @@ async function run() { const sarifPath = getRequiredInput("sarif_file"); const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); - const uploadResults = await uploadSarif( + const uploadResults = await processAndUploadSarif( logger, features, "always", diff --git a/src/analyze-action.ts b/src/analyze-action.ts index fb510a727..f69845d2f 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -52,7 +52,7 @@ import { } from "./trap-caching"; import * as uploadLib from "./upload-lib"; import { UploadResult } from "./upload-lib"; -import { uploadSarif } from "./upload-sarif"; +import { processAndUploadSarif } from "./upload-sarif"; import * as util from "./util"; interface AnalysisStatusReport @@ -352,7 +352,7 @@ async function run() { const category = actionsUtil.getOptionalInput("category"); if (await features.getValue(Feature.AnalyzeUseNewUpload)) { - uploadResults = await uploadSarif( + uploadResults = await processAndUploadSarif( logger, features, uploadKind, diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index 8a8bca8b7..087179dae 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -16,7 +16,7 @@ import { isThirdPartyAnalysis, } from "./status-report"; import * as upload_lib from "./upload-lib"; -import { uploadSarif } from "./upload-sarif"; +import { processAndUploadSarif } from "./upload-sarif"; import { ConfigurationError, checkActionVersion, @@ -90,7 +90,7 @@ async function run() { const checkoutPath = actionsUtil.getRequiredInput("checkout_path"); const category = actionsUtil.getOptionalInput("category"); - const uploadResults = await uploadSarif( + const uploadResults = await processAndUploadSarif( logger, features, "always", diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index cce178060..2c0f7fc52 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -9,7 +9,7 @@ import { getRunnerLogger } from "./logging"; import { createFeatures, setupTests } from "./testing-utils"; import { UploadResult } from "./upload-lib"; import * as uploadLib from "./upload-lib"; -import { uploadSarif } from "./upload-sarif"; +import { processAndUploadSarif } from "./upload-sarif"; import * as util from "./util"; setupTests(test); @@ -39,7 +39,7 @@ function mockPostProcessSarifFiles() { return postProcessSarifFiles; } -const uploadSarifMacro = test.macro({ +const processAndUploadSarifMacro = test.macro({ exec: async ( t: ExecutionContext, sarifFiles: string[], @@ -71,7 +71,7 @@ const uploadSarifMacro = test.macro({ fs.writeFileSync(sarifFile, ""); } - const actual = await uploadSarif( + const actual = await processAndUploadSarif( logger, features, "always", @@ -116,12 +116,12 @@ const uploadSarifMacro = test.macro({ } }); }, - title: (providedTitle = "") => `uploadSarif - ${providedTitle}`, + title: (providedTitle = "") => `processAndUploadSarif - ${providedTitle}`, }); test( "SARIF file", - uploadSarifMacro, + processAndUploadSarifMacro, ["test.sarif"], (tempDir) => path.join(tempDir, "test.sarif"), { @@ -136,7 +136,7 @@ test( test( "JSON file", - uploadSarifMacro, + processAndUploadSarifMacro, ["test.json"], (tempDir) => path.join(tempDir, "test.json"), { @@ -151,7 +151,7 @@ test( test( "Code Scanning files", - uploadSarifMacro, + processAndUploadSarifMacro, ["test.json", "test.sarif"], undefined, { @@ -167,7 +167,7 @@ test( test( "Code Quality file", - uploadSarifMacro, + processAndUploadSarifMacro, ["test.quality.sarif"], (tempDir) => path.join(tempDir, "test.quality.sarif"), { @@ -182,7 +182,7 @@ test( test( "Mixed files", - uploadSarifMacro, + processAndUploadSarifMacro, ["test.sarif", "test.quality.sarif"], undefined, { @@ -203,7 +203,7 @@ test( }, ); -test("uploadSarif doesn't upload if upload is disabled", async (t) => { +test("processAndUploadSarif doesn't upload if upload is disabled", async (t) => { await util.withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const features = createFeatures([]); @@ -216,7 +216,7 @@ test("uploadSarif doesn't upload if upload is disabled", async (t) => { fs.writeFileSync(toFullPath("test.sarif"), ""); fs.writeFileSync(toFullPath("test.quality.sarif"), ""); - const actual = await uploadSarif(logger, features, "never", "", tempDir); + const actual = await processAndUploadSarif(logger, features, "never", "", tempDir); t.truthy(actual); t.assert(postProcessSarifFiles.calledTwice); @@ -224,7 +224,7 @@ test("uploadSarif doesn't upload if upload is disabled", async (t) => { }); }); -test("uploadSarif writes processed SARIF files if output directory is provided", async (t) => { +test("processAndUploadSarif writes processed SARIF files if output directory is provided", async (t) => { await util.withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const features = createFeatures([]); @@ -237,7 +237,7 @@ test("uploadSarif writes processed SARIF files if output directory is provided", fs.writeFileSync(toFullPath("test.quality.sarif"), ""); const processedOutPath = path.join(tempDir, "processed"); - const actual = await uploadSarif( + const actual = await processAndUploadSarif( logger, features, "never", diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index 87990089e..8774f15d7 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -23,7 +23,7 @@ export type UploadSarifResults = Partial< * * @returns A partial mapping from analysis kinds to the upload results. */ -export async function uploadSarif( +export async function processAndUploadSarif( logger: Logger, features: FeatureEnablement, uploadKind: UploadKind, From 8ff870a6c2a5dce88896ad8d662b355981101585 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 19:12:38 +0100 Subject: [PATCH 13/17] Rename new input to `processed-sarif-path` --- .github/workflows/__quality-queries.yml | 2 +- analyze/action.yml | 2 +- lib/analyze-action.js | 2 +- pr-checks/checks/quality-queries.yml | 2 +- src/analyze-action.ts | 2 +- src/upload-lib.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/__quality-queries.yml b/.github/workflows/__quality-queries.yml index d75f1520f..67ffa3293 100644 --- a/.github/workflows/__quality-queries.yml +++ b/.github/workflows/__quality-queries.yml @@ -80,7 +80,7 @@ jobs: with: output: ${{ runner.temp }}/results upload-database: false - post-process-output: ${{ runner.temp }}/processed + processed-sarif-path: ${{ runner.temp }}/processed - name: Upload security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 diff --git a/analyze/action.yml b/analyze/action.yml index 438406761..81af1594c 100644 --- a/analyze/action.yml +++ b/analyze/action.yml @@ -70,7 +70,7 @@ inputs: description: Whether to upload the resulting CodeQL database required: false default: "true" - post-process-output: + processed-sarif-path: description: >- Before uploading the SARIF files produced by the CodeQL CLI, the CodeQL Action may perform some post-processing on them. Ordinarily, these processed SARIF files are not saved to disk. However, if a path is provided as an diff --git a/lib/analyze-action.js b/lib/analyze-action.js index c5b340b28..0537bf934 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -96433,7 +96433,7 @@ async function run() { checkoutPath, outputDir, category, - getOptionalInput("post-process-output") + getOptionalInput("processed-sarif-path") ); } else { uploadResults = {}; diff --git a/pr-checks/checks/quality-queries.yml b/pr-checks/checks/quality-queries.yml index 2304daacb..c71a8378d 100644 --- a/pr-checks/checks/quality-queries.yml +++ b/pr-checks/checks/quality-queries.yml @@ -36,7 +36,7 @@ steps: with: output: "${{ runner.temp }}/results" upload-database: false - post-process-output: "${{ runner.temp }}/processed" + processed-sarif-path: "${{ runner.temp }}/processed" - name: Upload security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 diff --git a/src/analyze-action.ts b/src/analyze-action.ts index f69845d2f..91cf55bbf 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -359,7 +359,7 @@ async function run() { checkoutPath, outputDir, category, - actionsUtil.getOptionalInput("post-process-output"), + actionsUtil.getOptionalInput("processed-sarif-path"), ); } else { uploadResults = {}; diff --git a/src/upload-lib.ts b/src/upload-lib.ts index db2bafd11..f38ae22be 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -763,7 +763,7 @@ export async function postProcessSarifFiles( * Writes the processed SARIF file to disk, if needed based on `pathInput` or the `SARIF_DUMP_DIR`. * * @param logger The logger to use. - * @param pathInput The input provided for `post-process-output`. + * @param pathInput The input provided for `processed-sarif-path`. * @param uploadTarget The upload target. * @param processingResults The results of post-processing SARIF files. */ From aed27f72313127fc271ae8f79794ab198d73f146 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 22 Oct 2025 19:25:34 +0100 Subject: [PATCH 14/17] Fix linter issue --- src/upload-sarif.test.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index 2c0f7fc52..873bf4dff 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -216,7 +216,13 @@ test("processAndUploadSarif doesn't upload if upload is disabled", async (t) => fs.writeFileSync(toFullPath("test.sarif"), ""); fs.writeFileSync(toFullPath("test.quality.sarif"), ""); - const actual = await processAndUploadSarif(logger, features, "never", "", tempDir); + const actual = await processAndUploadSarif( + logger, + features, + "never", + "", + tempDir, + ); t.truthy(actual); t.assert(postProcessSarifFiles.calledTwice); From f48b54af10d7d404c3163cb0d58bd6f7f2e2dfcb Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 23 Oct 2025 13:33:36 +0100 Subject: [PATCH 15/17] Fix fallback not being guarded by `uploadKind` check --- lib/analyze-action.js | 5 ++++- src/analyze-action.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 0537bf934..3a4ce819f 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -96435,7 +96435,7 @@ async function run() { category, getOptionalInput("processed-sarif-path") ); - } else { + } else if (uploadKind === "always") { uploadResults = {}; if (isCodeScanningEnabled(config)) { uploadResults["code-scanning" /* CodeScanning */] = await uploadFiles( @@ -96457,6 +96457,9 @@ async function run() { CodeQuality ); } + } else { + uploadResults = {}; + logger.info("Not uploading results"); } if (uploadResults["code-scanning" /* CodeScanning */] !== void 0) { core14.setOutput( diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 91cf55bbf..50102328f 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -361,7 +361,7 @@ async function run() { category, actionsUtil.getOptionalInput("processed-sarif-path"), ); - } else { + } else if (uploadKind === "always") { uploadResults = {}; if (isCodeScanningEnabled(config)) { @@ -387,6 +387,9 @@ async function run() { analyses.CodeQuality, ); } + } else { + uploadResults = {}; + logger.info("Not uploading results"); } // Set the SARIF id outputs only if we have results for them, to avoid From f0452d53667194f9f75d659eb44b683248333ef9 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 24 Oct 2025 10:20:25 +0100 Subject: [PATCH 16/17] Consistently use "post-processing" --- .github/workflows/__quality-queries.yml | 8 ++--- analyze/action.yml | 4 +-- lib/analyze-action.js | 36 +++++++++---------- lib/init-action-post.js | 12 +++---- lib/upload-lib.js | 26 +++++++------- lib/upload-sarif-action.js | 32 ++++++++--------- pr-checks/checks/quality-queries.yml | 8 ++--- src/analyze-action.ts | 6 ++-- src/upload-lib.ts | 33 +++++++++-------- src/upload-sarif-action.ts | 4 +-- src/upload-sarif.test.ts | 47 +++++++++++++------------ src/upload-sarif.ts | 24 ++++++------- 12 files changed, 121 insertions(+), 119 deletions(-) diff --git a/.github/workflows/__quality-queries.yml b/.github/workflows/__quality-queries.yml index 67ffa3293..d01015316 100644 --- a/.github/workflows/__quality-queries.yml +++ b/.github/workflows/__quality-queries.yml @@ -80,7 +80,7 @@ jobs: with: output: ${{ runner.temp }}/results upload-database: false - processed-sarif-path: ${{ runner.temp }}/processed + post-processed-sarif-path: ${{ runner.temp }}/post-processed - name: Upload security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 @@ -97,12 +97,12 @@ jobs: quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json path: ${{ runner.temp }}/results/javascript.quality.sarif retention-days: 7 - - name: Upload processed SARIF + - name: Upload post-processed SARIF uses: actions/upload-artifact@v4 with: name: | - processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json - path: ${{ runner.temp }}/processed + post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json + path: ${{ runner.temp }}/post-processed retention-days: 7 if-no-files-found: error - name: Check quality query does not appear in security SARIF diff --git a/analyze/action.yml b/analyze/action.yml index 81af1594c..fd6719df4 100644 --- a/analyze/action.yml +++ b/analyze/action.yml @@ -70,10 +70,10 @@ inputs: description: Whether to upload the resulting CodeQL database required: false default: "true" - processed-sarif-path: + post-processed-sarif-path: description: >- Before uploading the SARIF files produced by the CodeQL CLI, the CodeQL Action may perform some post-processing - on them. Ordinarily, these processed SARIF files are not saved to disk. However, if a path is provided as an + on them. Ordinarily, these post-processed SARIF files are not saved to disk. However, if a path is provided as an argument for this input, they are written to the specified directory. required: false wait-for-processing: diff --git a/lib/analyze-action.js b/lib/analyze-action.js index af56df20f..a897de825 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -95901,7 +95901,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo return payloadObj; } async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { - logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); + logger.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; category = analysis.fixCategory(logger, category); @@ -95934,17 +95934,17 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } -async function writeProcessedFiles(logger, pathInput, uploadTarget, processingResults) { +async function writePostProcessedFiles(logger, pathInput, uploadTarget, postProcessingResults) { const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; if (outputPath !== void 0) { dumpSarifFile( - JSON.stringify(processingResults.sarif), + JSON.stringify(postProcessingResults.sarif), outputPath, logger, uploadTarget ); } else { - logger.debug(`Not writing processed SARIF files.`); + logger.debug(`Not writing post-processed SARIF files.`); } } async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { @@ -95970,16 +95970,16 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); - return uploadProcessedFiles( + return uploadPostProcessedFiles( logger, checkoutPath, uploadTarget, processingResults ); } -async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { +async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, postProcessingResults) { logger.startGroup(`Uploading ${uploadTarget.name} results`); - const sarif = processingResults.sarif; + const sarif = postProcessingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -95991,13 +95991,13 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - processingResults.analysisKey, + postProcessingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - processingResults.environment, + postProcessingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); @@ -96191,7 +96191,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { +async function postProcessAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, postProcessedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -96201,7 +96201,7 @@ async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifGroups )) { const analysisConfig = getAnalysisConfig(analysisKind); - const processingResults = await postProcessSarifFiles( + const postProcessingResults = await postProcessSarifFiles( logger, features, checkoutPath, @@ -96209,18 +96209,18 @@ async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, category, analysisConfig ); - await writeProcessedFiles( + await writePostProcessedFiles( logger, - processedOutputPath, + postProcessedOutputPath, analysisConfig, - processingResults + postProcessingResults ); if (uploadKind === "always") { - uploadResults[analysisKind] = await uploadProcessedFiles( + uploadResults[analysisKind] = await uploadPostProcessedFiles( logger, checkoutPath, analysisConfig, - processingResults + postProcessingResults ); } } @@ -96428,14 +96428,14 @@ async function run() { const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); if (await features.getValue("analyze_use_new_upload" /* AnalyzeUseNewUpload */)) { - uploadResults = await processAndUploadSarif( + uploadResults = await postProcessAndUploadSarif( logger, features, uploadKind, checkoutPath, outputDir, category, - getOptionalInput("processed-sarif-path") + getOptionalInput("post-processed-sarif-path") ); } else if (uploadKind === "always") { uploadResults = {}; diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 1d89c9831..a7bd4c760 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -133312,7 +133312,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo return payloadObj; } async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { - logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); + logger.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; category = analysis.fixCategory(logger, category); @@ -133368,16 +133368,16 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); - return uploadProcessedFiles( + return uploadPostProcessedFiles( logger, checkoutPath, uploadTarget, processingResults ); } -async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { +async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, postProcessingResults) { logger.startGroup(`Uploading ${uploadTarget.name} results`); - const sarif = processingResults.sarif; + const sarif = postProcessingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -133389,13 +133389,13 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - processingResults.analysisKey, + postProcessingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - processingResults.environment, + postProcessingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); diff --git a/lib/upload-lib.js b/lib/upload-lib.js index ee0ae0d53..0d35b5f27 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -84855,11 +84855,11 @@ __export(upload_lib_exports, { throwIfCombineSarifFilesDisabled: () => throwIfCombineSarifFilesDisabled, uploadFiles: () => uploadFiles, uploadPayload: () => uploadPayload, - uploadProcessedFiles: () => uploadProcessedFiles, + uploadPostProcessedFiles: () => uploadPostProcessedFiles, validateSarifFileSchema: () => validateSarifFileSchema, validateUniqueCategory: () => validateUniqueCategory, waitForProcessing: () => waitForProcessing, - writeProcessedFiles: () => writeProcessedFiles + writePostProcessedFiles: () => writePostProcessedFiles }); module.exports = __toCommonJS(upload_lib_exports); var fs13 = __toESM(require("fs")); @@ -92715,7 +92715,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo return payloadObj; } async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { - logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); + logger.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; category = analysis.fixCategory(logger, category); @@ -92748,17 +92748,17 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } -async function writeProcessedFiles(logger, pathInput, uploadTarget, processingResults) { +async function writePostProcessedFiles(logger, pathInput, uploadTarget, postProcessingResults) { const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; if (outputPath !== void 0) { dumpSarifFile( - JSON.stringify(processingResults.sarif), + JSON.stringify(postProcessingResults.sarif), outputPath, logger, uploadTarget ); } else { - logger.debug(`Not writing processed SARIF files.`); + logger.debug(`Not writing post-processed SARIF files.`); } } async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { @@ -92784,16 +92784,16 @@ async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features category, uploadTarget ); - return uploadProcessedFiles( + return uploadPostProcessedFiles( logger, checkoutPath, uploadTarget, processingResults ); } -async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { +async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, postProcessingResults) { logger.startGroup(`Uploading ${uploadTarget.name} results`); - const sarif = processingResults.sarif; + const sarif = postProcessingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -92805,13 +92805,13 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - processingResults.analysisKey, + postProcessingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - processingResults.environment, + postProcessingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); @@ -93019,11 +93019,11 @@ function filterAlertsByDiffRange(logger, sarif) { throwIfCombineSarifFilesDisabled, uploadFiles, uploadPayload, - uploadProcessedFiles, + uploadPostProcessedFiles, validateSarifFileSchema, validateUniqueCategory, waitForProcessing, - writeProcessedFiles + writePostProcessedFiles }); /*! Bundled license information: diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index f5e487ef7..f11fd9e40 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93371,7 +93371,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo return payloadObj; } async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, category, analysis) { - logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); + logger.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarif; category = analysis.fixCategory(logger, category); @@ -93404,22 +93404,22 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, ); return { sarif, analysisKey, environment }; } -async function writeProcessedFiles(logger, pathInput, uploadTarget, processingResults) { +async function writePostProcessedFiles(logger, pathInput, uploadTarget, postProcessingResults) { const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; if (outputPath !== void 0) { dumpSarifFile( - JSON.stringify(processingResults.sarif), + JSON.stringify(postProcessingResults.sarif), outputPath, logger, uploadTarget ); } else { - logger.debug(`Not writing processed SARIF files.`); + logger.debug(`Not writing post-processed SARIF files.`); } } -async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processingResults) { +async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, postProcessingResults) { logger.startGroup(`Uploading ${uploadTarget.name} results`); - const sarif = processingResults.sarif; + const sarif = postProcessingResults.sarif; const toolNames = getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); validateUniqueCategory(sarif, uploadTarget.sentinelPrefix); @@ -93431,13 +93431,13 @@ async function uploadProcessedFiles(logger, checkoutPath, uploadTarget, processi const payload = buildPayload( await getCommitOid(checkoutPath), await getRef(), - processingResults.analysisKey, + postProcessingResults.analysisKey, getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, getWorkflowRunID(), getWorkflowRunAttempt(), checkoutURI, - processingResults.environment, + postProcessingResults.environment, toolNames, await determineBaseBranchHeadCommitOid() ); @@ -93631,7 +93631,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // src/upload-sarif.ts -async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, processedOutputPath) { +async function postProcessAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifPath, category, postProcessedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger, sarifPath @@ -93641,7 +93641,7 @@ async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, sarifGroups )) { const analysisConfig = getAnalysisConfig(analysisKind); - const processingResults = await postProcessSarifFiles( + const postProcessingResults = await postProcessSarifFiles( logger, features, checkoutPath, @@ -93649,18 +93649,18 @@ async function processAndUploadSarif(logger, features, uploadKind, checkoutPath, category, analysisConfig ); - await writeProcessedFiles( + await writePostProcessedFiles( logger, - processedOutputPath, + postProcessedOutputPath, analysisConfig, - processingResults + postProcessingResults ); if (uploadKind === "always") { - uploadResults[analysisKind] = await uploadProcessedFiles( + uploadResults[analysisKind] = await uploadPostProcessedFiles( logger, checkoutPath, analysisConfig, - processingResults + postProcessingResults ); } } @@ -93714,7 +93714,7 @@ async function run() { const sarifPath = getRequiredInput("sarif_file"); const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); - const uploadResults = await processAndUploadSarif( + const uploadResults = await postProcessAndUploadSarif( logger, features, "always", diff --git a/pr-checks/checks/quality-queries.yml b/pr-checks/checks/quality-queries.yml index c71a8378d..ec88e44b3 100644 --- a/pr-checks/checks/quality-queries.yml +++ b/pr-checks/checks/quality-queries.yml @@ -36,7 +36,7 @@ steps: with: output: "${{ runner.temp }}/results" upload-database: false - processed-sarif-path: "${{ runner.temp }}/processed" + post-processed-sarif-path: "${{ runner.temp }}/post-processed" - name: Upload security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 @@ -53,12 +53,12 @@ steps: quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json path: "${{ runner.temp }}/results/javascript.quality.sarif" retention-days: 7 - - name: Upload processed SARIF + - name: Upload post-processed SARIF uses: actions/upload-artifact@v4 with: name: | - processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json - path: "${{ runner.temp }}/processed" + post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json + path: "${{ runner.temp }}/post-processed" retention-days: 7 if-no-files-found: error - name: Check quality query does not appear in security SARIF diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 50102328f..9ba010855 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -52,7 +52,7 @@ import { } from "./trap-caching"; import * as uploadLib from "./upload-lib"; import { UploadResult } from "./upload-lib"; -import { processAndUploadSarif } from "./upload-sarif"; +import { postProcessAndUploadSarif } from "./upload-sarif"; import * as util from "./util"; interface AnalysisStatusReport @@ -352,14 +352,14 @@ async function run() { const category = actionsUtil.getOptionalInput("category"); if (await features.getValue(Feature.AnalyzeUseNewUpload)) { - uploadResults = await processAndUploadSarif( + uploadResults = await postProcessAndUploadSarif( logger, features, uploadKind, checkoutPath, outputDir, category, - actionsUtil.getOptionalInput("processed-sarif-path"), + actionsUtil.getOptionalInput("post-processed-sarif-path"), ); } else if (uploadKind === "always") { uploadResults = {}; diff --git a/src/upload-lib.ts b/src/upload-lib.ts index f38ae22be..aa8bb6176 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -715,7 +715,7 @@ export async function postProcessSarifFiles( category: string | undefined, analysis: analyses.AnalysisConfig, ): Promise { - logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); + logger.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); @@ -760,18 +760,18 @@ export async function postProcessSarifFiles( } /** - * Writes the processed SARIF file to disk, if needed based on `pathInput` or the `SARIF_DUMP_DIR`. + * Writes the post-processed SARIF file to disk, if needed based on `pathInput` or the `SARIF_DUMP_DIR`. * * @param logger The logger to use. - * @param pathInput The input provided for `processed-sarif-path`. + * @param pathInput The input provided for `post-processed-sarif-path`. * @param uploadTarget The upload target. * @param processingResults The results of post-processing SARIF files. */ -export async function writeProcessedFiles( +export async function writePostProcessedFiles( logger: Logger, pathInput: string | undefined, uploadTarget: analyses.AnalysisConfig, - processingResults: PostProcessingResults, + postProcessingResults: PostProcessingResults, ) { // If there's an explicit input, use that. Otherwise, use the value from the environment variable. const outputPath = pathInput || process.env[EnvVar.SARIF_DUMP_DIR]; @@ -779,13 +779,13 @@ export async function writeProcessedFiles( // If we have an output path, write the SARIF file to it. if (outputPath !== undefined) { dumpSarifFile( - JSON.stringify(processingResults.sarif), + JSON.stringify(postProcessingResults.sarif), outputPath, logger, uploadTarget, ); } else { - logger.debug(`Not writing processed SARIF files.`); + logger.debug(`Not writing post-processed SARIF files.`); } } @@ -836,7 +836,7 @@ async function uploadSpecifiedFiles( uploadTarget, ); - return uploadProcessedFiles( + return uploadPostProcessedFiles( logger, checkoutPath, uploadTarget, @@ -845,25 +845,24 @@ async function uploadSpecifiedFiles( } /** - * Uploads the results of processing SARIF files to the specified upload target. + * Uploads the results of post-processing SARIF files to the specified upload target. * * @param logger The logger to use. * @param checkoutPath The path at which the repository was checked out. * @param uploadTarget The analysis configuration. - * @param processingResults The results of post-processing SARIF files. + * @param postProcessingResults The results of post-processing SARIF files. * - * @returns The results of uploading the `processingResults` to `uploadTarget`. + * @returns The results of uploading the `postProcessingResults` to `uploadTarget`. */ -export async function uploadProcessedFiles( +export async function uploadPostProcessedFiles( logger: Logger, checkoutPath: string, uploadTarget: analyses.AnalysisConfig, - processingResults: PostProcessingResults, + postProcessingResults: PostProcessingResults, ): Promise { logger.startGroup(`Uploading ${uploadTarget.name} results`); - const sarif = processingResults.sarif; - + const sarif = postProcessingResults.sarif; const toolNames = util.getToolNames(sarif); logger.debug(`Validating that each SARIF run has a unique category`); @@ -878,13 +877,13 @@ export async function uploadProcessedFiles( const payload = buildPayload( await gitUtils.getCommitOid(checkoutPath), await gitUtils.getRef(), - processingResults.analysisKey, + postProcessingResults.analysisKey, util.getRequiredEnvParam("GITHUB_WORKFLOW"), zippedSarif, actionsUtil.getWorkflowRunID(), actionsUtil.getWorkflowRunAttempt(), checkoutURI, - processingResults.environment, + postProcessingResults.environment, toolNames, await gitUtils.determineBaseBranchHeadCommitOid(), ); diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index 087179dae..338c9b6dc 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -16,7 +16,7 @@ import { isThirdPartyAnalysis, } from "./status-report"; import * as upload_lib from "./upload-lib"; -import { processAndUploadSarif } from "./upload-sarif"; +import { postProcessAndUploadSarif } from "./upload-sarif"; import { ConfigurationError, checkActionVersion, @@ -90,7 +90,7 @@ async function run() { const checkoutPath = actionsUtil.getRequiredInput("checkout_path"); const category = actionsUtil.getOptionalInput("category"); - const uploadResults = await processAndUploadSarif( + const uploadResults = await postProcessAndUploadSarif( logger, features, "always", diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index 873bf4dff..d32c0c031 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -9,7 +9,7 @@ import { getRunnerLogger } from "./logging"; import { createFeatures, setupTests } from "./testing-utils"; import { UploadResult } from "./upload-lib"; import * as uploadLib from "./upload-lib"; -import { processAndUploadSarif } from "./upload-sarif"; +import { postProcessAndUploadSarif } from "./upload-sarif"; import * as util from "./util"; setupTests(test); @@ -39,7 +39,7 @@ function mockPostProcessSarifFiles() { return postProcessSarifFiles; } -const processAndUploadSarifMacro = test.macro({ +const postProcessAndUploadSarifMacro = test.macro({ exec: async ( t: ExecutionContext, sarifFiles: string[], @@ -54,14 +54,14 @@ const processAndUploadSarifMacro = test.macro({ const toFullPath = (filename: string) => path.join(tempDir, filename); const postProcessSarifFiles = mockPostProcessSarifFiles(); - const uploadProcessedFiles = sinon.stub( + const uploadPostProcessedFiles = sinon.stub( uploadLib, - "uploadProcessedFiles", + "uploadPostProcessedFiles", ); for (const analysisKind of Object.values(AnalysisKind)) { const analysisConfig = getAnalysisConfig(analysisKind); - uploadProcessedFiles + uploadPostProcessedFiles .withArgs(logger, sinon.match.any, analysisConfig, sinon.match.any) .resolves(expectedResult[analysisKind as AnalysisKind]?.uploadResult); } @@ -71,7 +71,7 @@ const processAndUploadSarifMacro = test.macro({ fs.writeFileSync(sarifFile, ""); } - const actual = await processAndUploadSarif( + const actual = await postProcessAndUploadSarif( logger, features, "always", @@ -104,7 +104,7 @@ const processAndUploadSarifMacro = test.macro({ t.is(actual[analysisKind], undefined); // Therefore, we also check that the mocked `uploadProcessedFiles` was not called for this analysis kind. t.assert( - !uploadProcessedFiles.calledWith( + !uploadPostProcessedFiles.calledWith( logger, sinon.match.any, getAnalysisConfig(analysisKind), @@ -121,7 +121,7 @@ const processAndUploadSarifMacro = test.macro({ test( "SARIF file", - processAndUploadSarifMacro, + postProcessAndUploadSarifMacro, ["test.sarif"], (tempDir) => path.join(tempDir, "test.sarif"), { @@ -136,7 +136,7 @@ test( test( "JSON file", - processAndUploadSarifMacro, + postProcessAndUploadSarifMacro, ["test.json"], (tempDir) => path.join(tempDir, "test.json"), { @@ -151,7 +151,7 @@ test( test( "Code Scanning files", - processAndUploadSarifMacro, + postProcessAndUploadSarifMacro, ["test.json", "test.sarif"], undefined, { @@ -167,7 +167,7 @@ test( test( "Code Quality file", - processAndUploadSarifMacro, + postProcessAndUploadSarifMacro, ["test.quality.sarif"], (tempDir) => path.join(tempDir, "test.quality.sarif"), { @@ -182,7 +182,7 @@ test( test( "Mixed files", - processAndUploadSarifMacro, + postProcessAndUploadSarifMacro, ["test.sarif", "test.quality.sarif"], undefined, { @@ -203,7 +203,7 @@ test( }, ); -test("processAndUploadSarif doesn't upload if upload is disabled", async (t) => { +test("postProcessAndUploadSarif doesn't upload if upload is disabled", async (t) => { await util.withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const features = createFeatures([]); @@ -211,12 +211,15 @@ test("processAndUploadSarif doesn't upload if upload is disabled", async (t) => const toFullPath = (filename: string) => path.join(tempDir, filename); const postProcessSarifFiles = mockPostProcessSarifFiles(); - const uploadProcessedFiles = sinon.stub(uploadLib, "uploadProcessedFiles"); + const uploadPostProcessedFiles = sinon.stub( + uploadLib, + "uploadPostProcessedFiles", + ); fs.writeFileSync(toFullPath("test.sarif"), ""); fs.writeFileSync(toFullPath("test.quality.sarif"), ""); - const actual = await processAndUploadSarif( + const actual = await postProcessAndUploadSarif( logger, features, "never", @@ -226,11 +229,11 @@ test("processAndUploadSarif doesn't upload if upload is disabled", async (t) => t.truthy(actual); t.assert(postProcessSarifFiles.calledTwice); - t.assert(uploadProcessedFiles.notCalled); + t.assert(uploadPostProcessedFiles.notCalled); }); }); -test("processAndUploadSarif writes processed SARIF files if output directory is provided", async (t) => { +test("postProcessAndUploadSarif writes post-processed SARIF files if output directory is provided", async (t) => { await util.withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); const features = createFeatures([]); @@ -242,22 +245,22 @@ test("processAndUploadSarif writes processed SARIF files if output directory is fs.writeFileSync(toFullPath("test.sarif"), ""); fs.writeFileSync(toFullPath("test.quality.sarif"), ""); - const processedOutPath = path.join(tempDir, "processed"); - const actual = await processAndUploadSarif( + const postProcessedOutPath = path.join(tempDir, "post-processed"); + const actual = await postProcessAndUploadSarif( logger, features, "never", "", tempDir, "", - processedOutPath, + postProcessedOutPath, ); t.truthy(actual); t.assert(postProcessSarifFiles.calledTwice); - t.assert(fs.existsSync(path.join(processedOutPath, "upload.sarif"))); + t.assert(fs.existsSync(path.join(postProcessedOutPath, "upload.sarif"))); t.assert( - fs.existsSync(path.join(processedOutPath, "upload.quality.sarif")), + fs.existsSync(path.join(postProcessedOutPath, "upload.quality.sarif")), ); }); }); diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index 8774f15d7..bc2c88698 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -11,7 +11,7 @@ export type UploadSarifResults = Partial< >; /** - * Finds SARIF files in `sarifPath` and uploads them to the appropriate services. + * Finds SARIF files in `sarifPath`, post-processes them, and uploads them to the appropriate services. * * @param logger The logger to use. * @param features Information about enabled features. @@ -19,18 +19,18 @@ export type UploadSarifResults = Partial< * @param checkoutPath The path where the repository was checked out at. * @param sarifPath The path to the file or directory to upload. * @param category The analysis category. - * @param processedOutputPath The path to a directory to which the post-processed SARIF files should be written to. + * @param postProcessedOutputPath The path to a directory to which the post-processed SARIF files should be written to. * * @returns A partial mapping from analysis kinds to the upload results. */ -export async function processAndUploadSarif( +export async function postProcessAndUploadSarif( logger: Logger, features: FeatureEnablement, uploadKind: UploadKind, checkoutPath: string, sarifPath: string, category?: string, - processedOutputPath?: string, + postProcessedOutputPath?: string, ): Promise { const sarifGroups = await upload_lib.getGroupedSarifFilePaths( logger, @@ -42,7 +42,7 @@ export async function processAndUploadSarif( sarifGroups, )) { const analysisConfig = analyses.getAnalysisConfig(analysisKind); - const processingResults = await upload_lib.postProcessSarifFiles( + const postProcessingResults = await upload_lib.postProcessSarifFiles( logger, features, checkoutPath, @@ -51,22 +51,22 @@ export async function processAndUploadSarif( analysisConfig, ); - // Write the processed SARIF files to disk. This will only write them if needed based on user inputs + // Write the post-processed SARIF files to disk. This will only write them if needed based on user inputs // or environment variables. - await upload_lib.writeProcessedFiles( + await upload_lib.writePostProcessedFiles( logger, - processedOutputPath, + postProcessedOutputPath, analysisConfig, - processingResults, + postProcessingResults, ); - // Only perform the actual upload of the processed files, if `uploadKind` is `always`. + // Only perform the actual upload of the post-processed files if `uploadKind` is `always`. if (uploadKind === "always") { - uploadResults[analysisKind] = await upload_lib.uploadProcessedFiles( + uploadResults[analysisKind] = await upload_lib.uploadPostProcessedFiles( logger, checkoutPath, analysisConfig, - processingResults, + postProcessingResults, ); } } From 710606cc35e2444ba84bdf7702dcb481f7380ae7 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 24 Oct 2025 14:42:36 +0100 Subject: [PATCH 17/17] Check that `outputPath` is non-empty --- lib/analyze-action.js | 2 +- lib/upload-lib.js | 2 +- lib/upload-sarif-action.js | 2 +- src/upload-lib.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index a897de825..7a8bf55fb 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -95936,7 +95936,7 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, } async function writePostProcessedFiles(logger, pathInput, uploadTarget, postProcessingResults) { const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (outputPath !== void 0) { + if (outputPath !== void 0 && outputPath.trim() !== "") { dumpSarifFile( JSON.stringify(postProcessingResults.sarif), outputPath, diff --git a/lib/upload-lib.js b/lib/upload-lib.js index 0d35b5f27..e19467442 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -92750,7 +92750,7 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, } async function writePostProcessedFiles(logger, pathInput, uploadTarget, postProcessingResults) { const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (outputPath !== void 0) { + if (outputPath !== void 0 && outputPath.trim() !== "") { dumpSarifFile( JSON.stringify(postProcessingResults.sarif), outputPath, diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index f11fd9e40..d91b83b42 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -93406,7 +93406,7 @@ async function postProcessSarifFiles(logger, features, checkoutPath, sarifPaths, } async function writePostProcessedFiles(logger, pathInput, uploadTarget, postProcessingResults) { const outputPath = pathInput || process.env["CODEQL_ACTION_SARIF_DUMP_DIR" /* SARIF_DUMP_DIR */]; - if (outputPath !== void 0) { + if (outputPath !== void 0 && outputPath.trim() !== "") { dumpSarifFile( JSON.stringify(postProcessingResults.sarif), outputPath, diff --git a/src/upload-lib.ts b/src/upload-lib.ts index aa8bb6176..573ca670c 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -776,8 +776,8 @@ export async function writePostProcessedFiles( // If there's an explicit input, use that. Otherwise, use the value from the environment variable. const outputPath = pathInput || process.env[EnvVar.SARIF_DUMP_DIR]; - // If we have an output path, write the SARIF file to it. - if (outputPath !== undefined) { + // If we have a non-empty output path, write the SARIF file to it. + if (outputPath !== undefined && outputPath.trim() !== "") { dumpSarifFile( JSON.stringify(postProcessingResults.sarif), outputPath,