From bf0e2ed66ebb6225e1bff230d79b6e8a38cfd8dc Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 12 Oct 2026 17:24:21 +0100 Subject: [PATCH 1/8] Log when we didn't get a normal configuration file --- lib/entry-points.js | 3 +++ src/init-action-post.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/entry-points.js b/lib/entry-points.js index 1a99a44427..1300b53b02 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -187232,6 +187232,9 @@ async function run4(action) { const tmpDir = getTemporaryDirectory(); config = await getConfig(tmpDir, logger2); if (config === void 0) { + logger2.debug( + "Will try to load the configuration file from an aborted 'init' step, since there is no regular one." + ); config = getAbortedInitConfig(action, tmpDir); } const gitHubVersion = config?.gitHubVersion ?? await getGitHubVersion(); diff --git a/src/init-action-post.ts b/src/init-action-post.ts index 88aac46229..071137f547 100644 --- a/src/init-action-post.ts +++ b/src/init-action-post.ts @@ -76,6 +76,9 @@ async function run(action: ActionState<["Base", "Logger", "Env"]>) { // Try to load the "failed" configuration file instead which may have been written by the `init` step // with a minimal configuration for this post-action. if (config === undefined) { + logger.debug( + "Will try to load the configuration file from an aborted 'init' step, since there is no regular one.", + ); config = getAbortedInitConfig(action, tmpDir); } From e180f803c567eb6be9cb9231f1643f535bb06cfe Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 15 Oct 2026 14:35:40 +0100 Subject: [PATCH 2/8] Allow to explicitly not skip the SARIF upload --- lib/entry-points.js | 5 +++-- src/util.test.ts | 30 +++++++++++++++++++++++++++++- src/util.ts | 10 +++++++--- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 1300b53b02..72559eea95 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -169889,8 +169889,9 @@ async function delay(milliseconds, opts) { function isGoodVersion(versionSpec) { return !BROKEN_VERSIONS.includes(versionSpec); } -function shouldSkipSarifUpload() { - return isInTestMode() || process.env["CODEQL_ACTION_SKIP_SARIF_UPLOAD" /* SKIP_SARIF_UPLOAD */] === "true"; +function shouldSkipSarifUpload(env = getEnv()) { + const skipSarifUpload = env.getOptional("CODEQL_ACTION_SKIP_SARIF_UPLOAD" /* SKIP_SARIF_UPLOAD */); + return skipSarifUpload !== "false" && (env.isSkippingUploadsInTests() || skipSarifUpload === "true"); } function getTestingEnvironment() { const testingEnvironment = process.env["CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */] || ""; diff --git a/src/util.test.ts b/src/util.test.ts index bca2b452e7..1a1f7677ea 100644 --- a/src/util.test.ts +++ b/src/util.test.ts @@ -11,7 +11,7 @@ import * as sinon from "sinon"; import * as api from "./api-client"; import { EnvVar } from "./environment"; import { getRunnerLogger } from "./logging"; -import { setupTests } from "./testing-utils"; +import { getTestEnv, setupTests } from "./testing-utils"; import * as util from "./util"; setupTests(test); @@ -493,3 +493,31 @@ test("Failure.orElse returns the default value for a failure result", (t) => { const result = new util.Failure(new Error("test error")); t.is(result.orElse("default value"), "default value"); }); + +test("shouldSkipSarifUpload", (t) => { + const env = getTestEnv(); + + // Don't skip by default + t.is(util.shouldSkipSarifUpload(env), false); + + // Skip in test mode + env.setAll({ + [EnvVar.TEST_MODE]: "true", + [EnvVar.SKIP_SARIF_UPLOAD]: undefined, + }); + t.is(util.shouldSkipSarifUpload(env), true); + + // Skip if explicitly requested + env.setAll({ + [EnvVar.TEST_MODE]: undefined, + [EnvVar.SKIP_SARIF_UPLOAD]: "true", + }); + t.is(util.shouldSkipSarifUpload(env), true); + + // Don't skip if explicitly requested + env.setAll({ + [EnvVar.TEST_MODE]: "true", + [EnvVar.SKIP_SARIF_UPLOAD]: "false", + }); + t.is(util.shouldSkipSarifUpload(env), false); +}); diff --git a/src/util.ts b/src/util.ts index 02e105d577..073ecf0a01 100644 --- a/src/util.ts +++ b/src/util.ts @@ -18,10 +18,10 @@ import type { Config } from "./config-utils"; import { EnvVar, getRequiredEnvParam, - isInTestMode, exportEnvVar, getEnv, type Env, + type ReadOnlyEnv, } from "./environment"; import * as json from "./json"; import { Language } from "./languages"; @@ -687,8 +687,12 @@ export function isGoodVersion(versionSpec: string) { /** * Returns whether we specifically want to skip uploading SARIF files. */ -export function shouldSkipSarifUpload(): boolean { - return isInTestMode() || process.env[EnvVar.SKIP_SARIF_UPLOAD] === "true"; +export function shouldSkipSarifUpload(env: ReadOnlyEnv = getEnv()): boolean { + const skipSarifUpload = env.getOptional(EnvVar.SKIP_SARIF_UPLOAD); + return ( + skipSarifUpload !== "false" && + (env.isSkippingUploadsInTests() || skipSarifUpload === "true") + ); } /** From b1c5d475ab063d2f18709e18aa0a990e49b1df8e Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 15 Oct 2026 14:40:34 +0100 Subject: [PATCH 3/8] Add and use `shouldSkipGenerateFailedSarif` --- lib/entry-points.js | 8 ++++++- src/environment.ts | 7 ++++++ src/init-action-post-helper.ts | 4 ++-- src/util.test.ts | 39 ++++++++++++++++++++++++++++++++++ src/util.ts | 15 +++++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 72559eea95..6a1e50a4c2 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -169889,6 +169889,12 @@ async function delay(milliseconds, opts) { function isGoodVersion(versionSpec) { return !BROKEN_VERSIONS.includes(versionSpec); } +function shouldSkipGenerateFailedSarif(env = getEnv()) { + const skipGenerateFailedSarif = env.getOptional( + "CODEQL_ACTION_SKIP_GENERATE_FAILED_SARIF" /* SKIP_GENERATE_FAILED_SARIF */ + ); + return skipGenerateFailedSarif !== "false" && (shouldSkipSarifUpload(env) || skipGenerateFailedSarif === "true"); +} function shouldSkipSarifUpload(env = getEnv()) { const skipSarifUpload = env.getOptional("CODEQL_ACTION_SKIP_SARIF_UPLOAD" /* SKIP_SARIF_UPLOAD */); return skipSarifUpload !== "false" && (env.isSkippingUploadsInTests() || skipSarifUpload === "true"); @@ -186904,7 +186910,7 @@ async function prepareFailedSarif(logger2, features, config) { } const jobName = getRequiredEnvParam("GITHUB_JOB"); const matrix = parseMatrixInput(getRequiredInput("matrix")); - if (shouldSkipSarifUpload()) { + if (shouldSkipGenerateFailedSarif()) { return new Failure({ upload_failed_run_skipped_because: "SARIF upload is disabled" }); diff --git a/src/environment.ts b/src/environment.ts index 9f61070257..32140baf05 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -165,6 +165,13 @@ export enum EnvVar { */ SARIF_DUMP_DIR = "CODEQL_ACTION_SARIF_DUMP_DIR", + /** + * Whether to skip generating a failed SARIF file. Intended for testing purposes. + * This setting is more specific than `CODEQL_ACTION_TEST_MODE` and + * `CODEQL_ACTION_SKIP_SARIF_UPLOAD`, which imply this option. + */ + SKIP_GENERATE_FAILED_SARIF = "CODEQL_ACTION_SKIP_GENERATE_FAILED_SARIF", + /** * Whether to skip uploading SARIF results to GitHub. Intended for testing purposes. * This setting is more specific than `CODEQL_ACTION_TEST_MODE`, which implies this option. diff --git a/src/init-action-post-helper.ts b/src/init-action-post-helper.ts index f9021b7893..38ff078711 100644 --- a/src/init-action-post-helper.ts +++ b/src/init-action-post-helper.ts @@ -44,7 +44,7 @@ import { getRequiredEnvParam, parseMatrixInput, Result, - shouldSkipSarifUpload, + shouldSkipGenerateFailedSarif, Success, wrapError, } from "./util"; @@ -115,7 +115,7 @@ async function prepareFailedSarif( const jobName = getRequiredEnvParam("GITHUB_JOB"); const matrix = parseMatrixInput(actionsUtil.getRequiredInput("matrix")); - if (shouldSkipSarifUpload()) { + if (shouldSkipGenerateFailedSarif()) { return new Failure({ upload_failed_run_skipped_because: "SARIF upload is disabled", }); diff --git a/src/util.test.ts b/src/util.test.ts index 1a1f7677ea..e7a7d3abd6 100644 --- a/src/util.test.ts +++ b/src/util.test.ts @@ -494,6 +494,45 @@ test("Failure.orElse returns the default value for a failure result", (t) => { t.is(result.orElse("default value"), "default value"); }); +test("shouldSkipGenerateFailedSarif", (t) => { + const env = getTestEnv(); + + // Don't skip by default + t.is(util.shouldSkipGenerateFailedSarif(env), false); + + // Skip in test mode + env.setAll({ + [EnvVar.TEST_MODE]: "true", + [EnvVar.SKIP_SARIF_UPLOAD]: undefined, + [EnvVar.SKIP_GENERATE_FAILED_SARIF]: undefined, + }); + t.is(util.shouldSkipGenerateFailedSarif(env), true); + + // Skip if explicitly requested + env.setAll({ + [EnvVar.TEST_MODE]: undefined, + [EnvVar.SKIP_SARIF_UPLOAD]: undefined, + [EnvVar.SKIP_GENERATE_FAILED_SARIF]: "true", + }); + t.is(util.shouldSkipGenerateFailedSarif(env), true); + + // Skip if not uploading SARIF + env.setAll({ + [EnvVar.TEST_MODE]: undefined, + [EnvVar.SKIP_SARIF_UPLOAD]: "true", + [EnvVar.SKIP_GENERATE_FAILED_SARIF]: undefined, + }); + t.is(util.shouldSkipGenerateFailedSarif(env), true); + + // Don't skip if explicitly requested + env.setAll({ + [EnvVar.TEST_MODE]: "true", + [EnvVar.SKIP_SARIF_UPLOAD]: "true", + [EnvVar.SKIP_GENERATE_FAILED_SARIF]: "false", + }); + t.is(util.shouldSkipGenerateFailedSarif(env), false); +}); + test("shouldSkipSarifUpload", (t) => { const env = getTestEnv(); diff --git a/src/util.ts b/src/util.ts index 073ecf0a01..ba0c3c7d46 100644 --- a/src/util.ts +++ b/src/util.ts @@ -684,6 +684,21 @@ export function isGoodVersion(versionSpec: string) { return !BROKEN_VERSIONS.includes(versionSpec); } +/** + * Returns whether we specifically want to skip generating a failed SARIF. + */ +export function shouldSkipGenerateFailedSarif( + env: ReadOnlyEnv = getEnv(), +): boolean { + const skipGenerateFailedSarif = env.getOptional( + EnvVar.SKIP_GENERATE_FAILED_SARIF, + ); + return ( + skipGenerateFailedSarif !== "false" && + (shouldSkipSarifUpload(env) || skipGenerateFailedSarif === "true") + ); +} + /** * Returns whether we specifically want to skip uploading SARIF files. */ From 2765b8f6f9148b0c7316458856e770ce850db1f5 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 15 Oct 2026 17:13:58 +0100 Subject: [PATCH 4/8] Propagate `Config` to `combineSarifFilesUsingCLI` --- lib/entry-points.js | 24 ++++++++++++++++-------- src/analyze-action.ts | 1 + src/init-action-post-helper.test.ts | 1 + src/init-action-post-helper.ts | 1 + src/upload-lib.ts | 21 +++++++++++++++------ src/upload-sarif-action.ts | 10 +++++++++- src/upload-sarif.test.ts | 6 ++++++ src/upload-sarif.ts | 3 +++ 8 files changed, 52 insertions(+), 15 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 6a1e50a4c2..28d1694c15 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -180021,7 +180021,7 @@ async function shouldDisableCombineSarifFiles(sarifObjects, githubVersion) { } return true; } -async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, logger2) { +async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, logger2, config) { const env = getEnv(); logger2.info("Combining SARIF files using the CodeQL CLI"); const sarifObjects = sarifFiles.map(readSarifFile); @@ -180042,7 +180042,6 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo } let codeQL; let tempDir = getTemporaryDirectory(); - const config = await getConfig(tempDir, logger2); if (config !== void 0) { codeQL = await getCodeQL(logger2, config.codeQLCmd); tempDir = config.tempDir; @@ -180327,7 +180326,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -async function postProcessSarifFiles(logger2, features, checkoutPath, sarifPaths, category, analysis) { +async function postProcessSarifFiles(logger2, features, config, checkoutPath, sarifPaths, category, analysis) { logger2.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); let sarifLog; @@ -180341,7 +180340,8 @@ async function postProcessSarifFiles(logger2, features, checkoutPath, sarifPaths sarifPaths, gitHubVersion, features, - logger2 + logger2, + config ); } else { const sarifPath = sarifPaths[0]; @@ -180374,13 +180374,14 @@ async function writePostProcessedFiles(logger2, pathInput, uploadTarget, postPro logger2.debug(`Not writing post-processed SARIF files.`); } } -async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger2, uploadTarget) { +async function uploadFiles(config, inputSarifPath, checkoutPath, category, features, logger2, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, uploadTarget.sarifPredicate ); return uploadSpecifiedFiles( sarifPaths, + config, checkoutPath, category, features, @@ -180388,10 +180389,11 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log uploadTarget ); } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger2, uploadTarget) { +async function uploadSpecifiedFiles(sarifPaths, config, checkoutPath, category, features, logger2, uploadTarget) { const processingResults = await postProcessSarifFiles( logger2, features, + config, checkoutPath, sarifPaths, category, @@ -180621,7 +180623,7 @@ function filterAlertsByDiffRange(logger2, sarifLog) { } // src/upload-sarif.ts -async function postProcessAndUploadSarif(logger2, features, uploadKind, checkoutPath, sarifPath, category, postProcessedOutputPath) { +async function postProcessAndUploadSarif(logger2, features, config, uploadKind, checkoutPath, sarifPath, category, postProcessedOutputPath) { const sarifGroups = await getGroupedSarifFilePaths( logger2, sarifPath @@ -180634,6 +180636,7 @@ async function postProcessAndUploadSarif(logger2, features, uploadKind, checkout const postProcessingResults = await postProcessSarifFiles( logger2, features, + config, checkoutPath, sarifFiles, category, @@ -180864,6 +180867,7 @@ async function run(action) { uploadResults = await postProcessAndUploadSarif( logger2, features, + config, uploadKind, checkoutPath, outputDir, @@ -186981,6 +186985,7 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger2) const failedSarif = failedSarifResult.value; logger2.info(`Uploading failed SARIF file ${failedSarif.sarifFile}`); const uploadResult = await uploadFiles( + config, failedSarif.sarifFile, failedSarif.checkoutPath, failedSarif.category, @@ -188460,11 +188465,12 @@ async function run8({ startedAt, logger: logger2 }) { const gitHubVersion = await getGitHubVersion(); checkActionVersion(getActionVersion(), gitHubVersion); persistInputs(); + const tempDir = getTemporaryDirectory(); const repositoryNwo = getRepositoryNwo(); const features = initFeatures( gitHubVersion, repositoryNwo, - getTemporaryDirectory(), + tempDir, logger2 ); const startingStatusReportBase = await createStatusReportBase( @@ -188481,9 +188487,11 @@ async function run8({ startedAt, logger: logger2 }) { const sarifPath = getRequiredInput("sarif_file"); const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); + const maybeConfig = await getConfig(tempDir, logger2); const uploadResults = await postProcessAndUploadSarif( logger2, features, + maybeConfig, "always", checkoutPath, sarifPath, diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 9efbb529b0..a11877b38c 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -361,6 +361,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) { uploadResults = await postProcessAndUploadSarif( logger, features, + config, uploadKind, checkoutPath, outputDir, diff --git a/src/init-action-post-helper.test.ts b/src/init-action-post-helper.test.ts index fd1f489f7a..554add71fc 100644 --- a/src/init-action-post-helper.test.ts +++ b/src/init-action-post-helper.test.ts @@ -793,6 +793,7 @@ async function testFailedSarifUpload( } t.true( uploadFiles.calledOnceWith( + config, sinon.match.string, sinon.match.string, category, diff --git a/src/init-action-post-helper.ts b/src/init-action-post-helper.ts index 38ff078711..b7b4da8e56 100644 --- a/src/init-action-post-helper.ts +++ b/src/init-action-post-helper.ts @@ -226,6 +226,7 @@ async function maybeUploadFailedSarif( logger.info(`Uploading failed SARIF file ${failedSarif.sarifFile}`); const uploadResult = await uploadLib.uploadFiles( + config, failedSarif.sarifFile, failedSarif.checkoutPath, failedSarif.category, diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 3c46c15198..7c6f2afeaf 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -12,7 +12,7 @@ import * as analyses from "./analyses"; import * as api from "./api-client"; import { getGitHubVersion, wrapApiConfigurationError } from "./api-client"; import { CodeQL, getCodeQL } from "./codeql"; -import { getConfig } from "./config-utils"; +import type { ActionConfig } from "./config/action-config"; import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils"; import { ActionsEnvVars, EnvVar, exportEnvVar } from "./environment"; import { FeatureEnablement } from "./feature-flags"; @@ -94,15 +94,19 @@ async function shouldDisableCombineSarifFiles( return true; } -// Takes a list of paths to sarif files and combines them together using the -// CLI `github merge-results` command when all SARIF files are produced by -// CodeQL. Otherwise, it will fall back to combining the files in the action. -// Returns the contents of the combined sarif file. +/** + * Takes a list of paths to sarif files and combines them together using the + * CLI `github merge-results` command when all SARIF files are produced by + * CodeQL. Otherwise, it will fall back to combining the files in the action. + * + * @returns The contents of the combined sarif file. + */ async function combineSarifFilesUsingCLI( sarifFiles: string[], gitHubVersion: GitHubVersion, features: FeatureEnablement, logger: Logger, + config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined, ): Promise> { const env = util.getEnv(); @@ -140,7 +144,6 @@ async function combineSarifFilesUsingCLI( let codeQL: CodeQL; let tempDir: string = actionsUtil.getTemporaryDirectory(); - const config = await getConfig(tempDir, logger); if (config !== undefined) { codeQL = await getCodeQL(logger, config.codeQLCmd); tempDir = config.tempDir; @@ -599,6 +602,7 @@ export interface PostProcessingResults { export async function postProcessSarifFiles( logger: Logger, features: FeatureEnablement, + config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined, checkoutPath: string, sarifPaths: string[], category: string | undefined, @@ -623,6 +627,7 @@ export async function postProcessSarifFiles( gitHubVersion, features, logger, + config, ); } else { const sarifPath = sarifPaths[0]; @@ -683,6 +688,7 @@ export async function writePostProcessedFiles( * to. */ export async function uploadFiles( + config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined, inputSarifPath: string, checkoutPath: string, category: string | undefined, @@ -697,6 +703,7 @@ export async function uploadFiles( return uploadSpecifiedFiles( sarifPaths, + config, checkoutPath, category, features, @@ -710,6 +717,7 @@ export async function uploadFiles( */ async function uploadSpecifiedFiles( sarifPaths: string[], + config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined, checkoutPath: string, category: string | undefined, features: FeatureEnablement, @@ -719,6 +727,7 @@ async function uploadSpecifiedFiles( const processingResults: PostProcessingResults = await postProcessSarifFiles( logger, features, + config, checkoutPath, sarifPaths, category, diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index d3437510ce..52dd12ec0e 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -5,6 +5,7 @@ import * as actionsUtil from "./actions-util"; import { getActionVersion, getTemporaryDirectory } from "./actions-util"; import * as analyses from "./analyses"; import { getGitHubVersion } from "./api-client"; +import { getConfig } from "./config-utils"; import { initFeatures } from "./feature-flags"; import { Logger } from "./logging"; import { getRepositoryNwo } from "./repository"; @@ -66,11 +67,12 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { // Make inputs accessible in the `post` step. actionsUtil.persistInputs(); + const tempDir = getTemporaryDirectory(); const repositoryNwo = getRepositoryNwo(); const features = initFeatures( gitHubVersion, repositoryNwo, - getTemporaryDirectory(), + tempDir, logger, ); @@ -91,9 +93,15 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { const checkoutPath = actionsUtil.getRequiredInput("checkout_path"); const category = actionsUtil.getOptionalInput("category"); + // Although we wouldn't typically expect there to be a configuration since we don't expect another + // CodeQL Action step to have come before `upload-sarif`, this has previously been the behaviour + // when `combineSarifFilesUsingCLI` called `getConfig` directly. Since the only effect of this would + // be that an existing CLI that was installed gets re-used, we maintain this behaviour. + const maybeConfig = await getConfig(tempDir, logger); const uploadResults = await postProcessAndUploadSarif( logger, features, + maybeConfig, "always", checkoutPath, sarifPath, diff --git a/src/upload-sarif.test.ts b/src/upload-sarif.test.ts index d310bce92a..033be70d0b 100644 --- a/src/upload-sarif.test.ts +++ b/src/upload-sarif.test.ts @@ -26,6 +26,7 @@ function mockPostProcessSarifFiles() { const analysisConfig = getAnalysisConfig(analysisKind); postProcessSarifFiles .withArgs( + sinon.match.object, sinon.match.any, sinon.match.any, sinon.match.any, @@ -75,9 +76,11 @@ const postProcessAndUploadSarifMacro = makeMacro({ fs.writeFileSync(sarifFile, ""); } + const config = undefined; const actual = await postProcessAndUploadSarif( logger, features, + config, "always", "", testPath, @@ -94,6 +97,7 @@ const postProcessAndUploadSarifMacro = makeMacro({ postProcessSarifFiles.calledWith( logger, features, + config, sinon.match.any, analysisKindResult.expectedFiles?.map(toFullPath) ?? fullSarifPaths, @@ -223,6 +227,7 @@ test.serial( const actual = await postProcessAndUploadSarif( logger, features, + undefined, "never", "", tempDir, @@ -253,6 +258,7 @@ test.serial( const actual = await postProcessAndUploadSarif( logger, features, + undefined, "never", "", tempDir, diff --git a/src/upload-sarif.ts b/src/upload-sarif.ts index bc2c886982..0a8d8a14a2 100644 --- a/src/upload-sarif.ts +++ b/src/upload-sarif.ts @@ -1,5 +1,6 @@ import { UploadKind } from "./actions-util"; import * as analyses from "./analyses"; +import type { ActionConfig } from "./config/action-config"; import { FeatureEnablement } from "./feature-flags"; import { Logger } from "./logging"; import * as upload_lib from "./upload-lib"; @@ -26,6 +27,7 @@ export type UploadSarifResults = Partial< export async function postProcessAndUploadSarif( logger: Logger, features: FeatureEnablement, + config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined, uploadKind: UploadKind, checkoutPath: string, sarifPath: string, @@ -45,6 +47,7 @@ export async function postProcessAndUploadSarif( const postProcessingResults = await upload_lib.postProcessSarifFiles( logger, features, + config, checkoutPath, sarifFiles, category, From 68eb797e87d2950905272866eed70ea43d0e2788 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 16 Oct 2026 13:06:58 +0100 Subject: [PATCH 5/8] Skip waiting for SARIF if nothing was uploaded --- lib/entry-points.js | 6 ++++++ src/upload-lib.ts | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/entry-points.js b/lib/entry-points.js index 28d1694c15..ea4f7c9bec 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -180478,6 +180478,12 @@ async function waitForProcessing(repositoryNwo, sarifID, logger2, options = { }) { logger2.startGroup("Waiting for processing to finish"); try { + if (shouldSkipSarifUpload()) { + logger2.info( + "Nothing to wait for, because SARIF upload is disabled by an environment variable and the SARIF was saved to disk." + ); + return; + } const client = getApiClient(); let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; if (process.env["NODE_ENV"] !== "test") { diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 7c6f2afeaf..7b0a17b30d 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -866,6 +866,16 @@ export async function waitForProcessing( ): Promise { logger.startGroup("Waiting for processing to finish"); try { + // If SARIF uplaod is disabled and we reach this point, then the file was written to disk and + // there is nothing to wait for. We still allow ourselves to get to this point so that we can + // see in the log that we would have waited for processing to finish if the upload had happened. + if (util.shouldSkipSarifUpload()) { + logger.info( + "Nothing to wait for, because SARIF upload is disabled by an environment variable and the SARIF was saved to disk.", + ); + return; + } + const client = api.getApiClient(); // Do an initial wait because processing will always take a minimum of 2-3 seconds From 850cc877c3a1f39aa94dd950d6bebcd4b0c0f27a Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 12 Oct 2026 17:23:44 +0100 Subject: [PATCH 6/8] Upload failed SARIF as workflow artifact in test mode --- lib/entry-points.js | 20 +++++++++++++++----- src/init-action-post-helper.ts | 19 ++++++++++++++++++- src/upload-lib.ts | 13 +++++++++---- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index ea4f7c9bec..05694644e4 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -178546,6 +178546,7 @@ __export(upload_lib_exports, { filterAlertsByDiffRange: () => filterAlertsByDiffRange, findSarifFilesInDir: () => findSarifFilesInDir, getGroupedSarifFilePaths: () => getGroupedSarifFilePaths, + getSavedPayloadPath: () => getSavedPayloadPath, populateRunAutomationDetails: () => populateRunAutomationDetails, postProcessSarifFiles: () => postProcessSarifFiles, readSarifFileOrThrow: () => readSarifFileOrThrow, @@ -180108,13 +180109,16 @@ function getAutomationID2(category, analysis_key, environment) { } return computeAutomationID(analysis_key, environment); } +function getSavedPayloadPath(analysisKind) { + return path19.join( + getTemporaryDirectory(), + `payload-${analysisKind}.json` + ); +} async function uploadPayload(payload, repositoryNwo, logger2, analysis) { logger2.info("Uploading results"); if (shouldSkipSarifUpload()) { - const payloadSaveFile = path19.join( - getTemporaryDirectory(), - `payload-${analysis.kind}.json` - ); + const payloadSaveFile = getSavedPayloadPath(analysis.kind); logger2.info( `SARIF upload disabled by an environment variable. Saving to ${payloadSaveFile}` ); @@ -187005,6 +187009,9 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger2) logger2, { isUnsuccessfulExecution: true } ); + if (uploadResult.sarifID && shouldSkipSarifUpload()) { + await uploadSarifArtifact(logger2, "test-mode-sarif", failedSarif); + } return uploadResult ? { ...uploadResult.statusReport, sarifID: uploadResult.sarifID } : {}; } async function maybeUploadFailedSarifArtifact(config, features, logger2) { @@ -187013,13 +187020,16 @@ async function maybeUploadFailedSarifArtifact(config, features, logger2) { return failedSarifResult.value; } const failedSarif = failedSarifResult.value; + return uploadSarifArtifact(logger2, "sarif-artifact", failedSarif); +} +async function uploadSarifArtifact(logger2, prefix, failedSarif) { logger2.info( `Uploading failed SARIF file ${failedSarif.sarifFile} as artifact` ); const gitHubVersion = await getGitHubVersion(); const client = await getArtifactUploaderClient(logger2, gitHubVersion.type); const suffix = getArtifactSuffix(getOptionalInput("matrix")); - const name = sanitizeArtifactName(`sarif-artifact-${suffix}`); + const name = sanitizeArtifactName(`${prefix}-${suffix}`); await client.uploadArtifact( name, [import_path8.default.normalize(failedSarif.sarifFile)], diff --git a/src/init-action-post-helper.ts b/src/init-action-post-helper.ts index b7b4da8e56..0f0062ca71 100644 --- a/src/init-action-post-helper.ts +++ b/src/init-action-post-helper.ts @@ -45,6 +45,7 @@ import { parseMatrixInput, Result, shouldSkipGenerateFailedSarif, + shouldSkipSarifUpload, Success, wrapError, } from "./util"; @@ -240,6 +241,14 @@ async function maybeUploadFailedSarif( logger, { isUnsuccessfulExecution: true }, ); + + // If SARIF upload is disabled for testing, `uploadFiles` will not have uploaded the failed + // SARIF file and instead will have written it to disk. Upload it as a workflow artifact so that + // we can inspect it in validation jobs. + if (uploadResult.sarifID && shouldSkipSarifUpload()) { + await uploadSarifArtifact(logger, "test-mode-sarif", failedSarif); + } + return uploadResult ? { ...uploadResult.statusReport, sarifID: uploadResult.sarifID } : {}; @@ -258,7 +267,15 @@ async function maybeUploadFailedSarifArtifact( } const failedSarif = failedSarifResult.value; + return uploadSarifArtifact(logger, "sarif-artifact", failedSarif); +} +/** Uploads a failed SARIF file as workflow artifact. */ +async function uploadSarifArtifact( + logger: Logger, + prefix: string, + failedSarif: FailedSarifInfo, +): Promise { logger.info( `Uploading failed SARIF file ${failedSarif.sarifFile} as artifact`, ); @@ -267,7 +284,7 @@ async function maybeUploadFailedSarifArtifact( const client = await getArtifactUploaderClient(logger, gitHubVersion.type); const suffix = getArtifactSuffix(actionsUtil.getOptionalInput("matrix")); - const name = sanitizeArtifactName(`sarif-artifact-${suffix}`); + const name = sanitizeArtifactName(`${prefix}-${suffix}`); await client.uploadArtifact( name, [path.normalize(failedSarif.sarifFile)], diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 7b0a17b30d..b327054fbe 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -231,6 +231,14 @@ function getAutomationID( return api.computeAutomationID(analysis_key, environment); } +/** Gets the path to a saved payload file for {@link analysisKind}. */ +export function getSavedPayloadPath(analysisKind: analyses.AnalysisKind) { + return path.join( + actionsUtil.getTemporaryDirectory(), + `payload-${analysisKind}.json`, + ); +} + /** * Upload the given payload. * If the request fails then this will retry a small number of times. @@ -245,10 +253,7 @@ export async function uploadPayload( logger.info("Uploading results"); if (util.shouldSkipSarifUpload()) { - const payloadSaveFile = path.join( - actionsUtil.getTemporaryDirectory(), - `payload-${analysis.kind}.json`, - ); + const payloadSaveFile = getSavedPayloadPath(analysis.kind); logger.info( `SARIF upload disabled by an environment variable. Saving to ${payloadSaveFile}`, ); From 3a61940e40b4ce6ee61ec04e6deb5e6cec32b868 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 16 Oct 2026 16:59:56 +0100 Subject: [PATCH 7/8] Improve logging in `uploadSarifArtifact` --- lib/entry-points.js | 29 ++++++++++++++++------------- src/init-action-post-helper.ts | 31 +++++++++++++++++-------------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 05694644e4..5ad162ce31 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -187023,19 +187023,22 @@ async function maybeUploadFailedSarifArtifact(config, features, logger2) { return uploadSarifArtifact(logger2, "sarif-artifact", failedSarif); } async function uploadSarifArtifact(logger2, prefix, failedSarif) { - logger2.info( - `Uploading failed SARIF file ${failedSarif.sarifFile} as artifact` - ); - const gitHubVersion = await getGitHubVersion(); - const client = await getArtifactUploaderClient(logger2, gitHubVersion.type); - const suffix = getArtifactSuffix(getOptionalInput("matrix")); - const name = sanitizeArtifactName(`${prefix}-${suffix}`); - await client.uploadArtifact( - name, - [import_path8.default.normalize(failedSarif.sarifFile)], - import_path8.default.normalize("..") - ); - return { sarifID: name }; + logger2.startGroup(`Uploading failed SARIF file as artifact`); + logger2.info(`Uploading '${failedSarif.sarifFile}' as artifact`); + try { + const gitHubVersion = await getGitHubVersion(); + const client = await getArtifactUploaderClient(logger2, gitHubVersion.type); + const suffix = getArtifactSuffix(getOptionalInput("matrix")); + const name = sanitizeArtifactName(`${prefix}-${suffix}`); + await client.uploadArtifact( + name, + [import_path8.default.normalize(failedSarif.sarifFile)], + import_path8.default.normalize("..") + ); + return { sarifID: name }; + } finally { + logger2.endGroup(); + } } async function tryUploadSarifIfRunFailed(config, repositoryNwo, features, logger2) { if (process.env["CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY" /* ANALYZE_DID_COMPLETE_SUCCESSFULLY */] === "true") { diff --git a/src/init-action-post-helper.ts b/src/init-action-post-helper.ts index 0f0062ca71..30a3e0a3e5 100644 --- a/src/init-action-post-helper.ts +++ b/src/init-action-post-helper.ts @@ -276,22 +276,25 @@ async function uploadSarifArtifact( prefix: string, failedSarif: FailedSarifInfo, ): Promise { - logger.info( - `Uploading failed SARIF file ${failedSarif.sarifFile} as artifact`, - ); - - const gitHubVersion = await getGitHubVersion(); - const client = await getArtifactUploaderClient(logger, gitHubVersion.type); + logger.startGroup(`Uploading failed SARIF file as artifact`); + logger.info(`Uploading '${failedSarif.sarifFile}' as artifact`); - const suffix = getArtifactSuffix(actionsUtil.getOptionalInput("matrix")); - const name = sanitizeArtifactName(`${prefix}-${suffix}`); - await client.uploadArtifact( - name, - [path.normalize(failedSarif.sarifFile)], - path.normalize(".."), - ); + try { + const gitHubVersion = await getGitHubVersion(); + const client = await getArtifactUploaderClient(logger, gitHubVersion.type); + + const suffix = getArtifactSuffix(actionsUtil.getOptionalInput("matrix")); + const name = sanitizeArtifactName(`${prefix}-${suffix}`); + await client.uploadArtifact( + name, + [path.normalize(failedSarif.sarifFile)], + path.normalize(".."), + ); - return { sarifID: name }; + return { sarifID: name }; + } finally { + logger.endGroup(); + } } /** From d6b8ed80f2f8c281cd39af11d2ed11b4f4aec2ce Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 16 Oct 2026 13:09:16 +0100 Subject: [PATCH 8/8] Ensure that `rootDirectory` is suitable for `sarifFile` in `uploadSarifArtifact` --- lib/entry-points.js | 2 +- src/init-action-post-helper.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 5ad162ce31..230d5b40fa 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -187033,7 +187033,7 @@ async function uploadSarifArtifact(logger2, prefix, failedSarif) { await client.uploadArtifact( name, [import_path8.default.normalize(failedSarif.sarifFile)], - import_path8.default.normalize("..") + import_path8.default.normalize(import_path8.default.dirname(failedSarif.sarifFile)) ); return { sarifID: name }; } finally { diff --git a/src/init-action-post-helper.ts b/src/init-action-post-helper.ts index 30a3e0a3e5..cfaab312fb 100644 --- a/src/init-action-post-helper.ts +++ b/src/init-action-post-helper.ts @@ -288,7 +288,7 @@ async function uploadSarifArtifact( await client.uploadArtifact( name, [path.normalize(failedSarif.sarifFile)], - path.normalize(".."), + path.normalize(path.dirname(failedSarif.sarifFile)), ); return { sarifID: name };