Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Move core upload-sarif logic to upload-sarif module
Note that this also fixes the format of the `sarif-ids` outputs to match what is documented
  • Loading branch information
mbg committed Sep 29, 2025
commit 9f452fad0f9ce6172a69b8e024ac62b9bf057c0e
2 changes: 1 addition & 1 deletion .github/workflows/__upload-quality-sarif.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 42 additions & 35 deletions lib/upload-sarif-action.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pr-checks/checks/upload-quality-sarif.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ steps:
ref: 'refs/heads/main'
sha: '5e235361806c361d4d3f8859e3c897658025a9a2'
- name: "Check output from `upload-sarif` step"
if: fromJSON(steps.upload-sarif.outputs.sarif-ids)[0].analysis != 'code-quality'
if: !(fromJSON(steps.upload-sarif.outputs.sarif-ids).code-quality)
run: exit 1
51 changes: 11 additions & 40 deletions src/upload-sarif-action.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as fs from "fs";

import * as core from "@actions/core";

import * as actionsUtil from "./actions-util";
Expand All @@ -18,7 +16,7 @@ import {
isThirdPartyAnalysis,
} from "./status-report";
import * as upload_lib from "./upload-lib";
import { findAndUpload } from "./upload-sarif";
import { uploadSarif } from "./upload-sarif";
import {
ConfigurationError,
checkActionVersion,
Expand Down Expand Up @@ -91,56 +89,29 @@ async function run() {
const sarifPath = actionsUtil.getRequiredInput("sarif_file");
const checkoutPath = actionsUtil.getRequiredInput("checkout_path");
const category = actionsUtil.getOptionalInput("category");
const pathStats = fs.lstatSync(sarifPath, { throwIfNoEntry: false });

if (pathStats === undefined) {
throw new ConfigurationError(`Path does not exist: ${sarifPath}.`);
}

const sarifIds: Array<{ analysis: string; id: string }> = [];
const uploadResult = await findAndUpload(
const uploadResults = await uploadSarif(
logger,
features,
sarifPath,
pathStats,
checkoutPath,
analyses.CodeScanning,
category,
);
if (uploadResult !== undefined) {
core.setOutput("sarif-id", uploadResult.sarifID);
sarifIds.push({
analysis: analyses.AnalysisKind.CodeScanning,
id: uploadResult.sarifID,
});
}

// If there are `.quality.sarif` files in `sarifPath`, then upload those to the code quality service.
const qualityUploadResult = await findAndUpload(
logger,
features,
sarifPath,
pathStats,
checkoutPath,
analyses.CodeQuality,
actionsUtil.fixCodeQualityCategory(logger, category),
category,
);
if (qualityUploadResult !== undefined) {
sarifIds.push({
analysis: analyses.AnalysisKind.CodeQuality,
id: qualityUploadResult.sarifID,
});
const codeScanningResult =
uploadResults[analyses.AnalysisKind.CodeScanning];
if (codeScanningResult !== undefined) {
core.setOutput("sarif-id", codeScanningResult.sarifID);
}
core.setOutput("sarif-ids", JSON.stringify(sarifIds));
core.setOutput("sarif-ids", JSON.stringify(uploadResults));

// We don't upload results in test mode, so don't wait for processing
if (isInTestMode()) {
core.debug("In test mode. Waiting for processing is disabled.");
} else if (actionsUtil.getRequiredInput("wait-for-processing") === "true") {
if (uploadResult !== undefined) {
if (codeScanningResult !== undefined) {
await upload_lib.waitForProcessing(
getRepositoryNwo(),
uploadResult.sarifID,
codeScanningResult.sarifID,
logger,
);
}
Expand All @@ -149,7 +120,7 @@ async function run() {
}
await sendSuccessStatusReport(
startedAt,
uploadResult?.statusReport || {},
codeScanningResult?.statusReport || {},
logger,
);
} catch (unwrappedError) {
Expand Down
66 changes: 64 additions & 2 deletions src/upload-sarif.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as fs from "fs";

import * as actionsUtil from "./actions-util";
import * as analyses from "./analyses";
import { Features } from "./feature-flags";
import { FeatureEnablement } from "./feature-flags";
import { Logger } from "./logging";
import * as upload_lib from "./upload-lib";
import { ConfigurationError } from "./util";

/**
* Searches for SARIF files for the given `analysis` in the given `sarifPath`.
Expand All @@ -20,7 +22,7 @@ import * as upload_lib from "./upload-lib";
*/
export async function findAndUpload(
logger: Logger,
features: Features,
features: FeatureEnablement,
sarifPath: string,
pathStats: fs.Stats,
checkoutPath: string,
Expand Down Expand Up @@ -58,3 +60,63 @@ export async function findAndUpload(

return undefined;
}

// Maps analysis kinds to SARIF IDs.
type UploadSarifResults = Partial<
Record<analyses.AnalysisKind, upload_lib.UploadResult>
>;

/**
* Finds SARIF files in `sarifPath` and uploads them to the appropriate services.
*
* @param logger The logger to use.
* @param features Information about enabled features.
* @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.
*
* @returns A partial mapping from analysis kinds to the upload results.
*/
export async function uploadSarif(
logger: Logger,
features: FeatureEnablement,
checkoutPath: string,
sarifPath: string,
category?: string,
): Promise<UploadSarifResults> {
const pathStats = fs.lstatSync(sarifPath, { throwIfNoEntry: false });

if (pathStats === undefined) {
throw new ConfigurationError(`Path does not exist: ${sarifPath}.`);
}

const uploadResults: UploadSarifResults = {};
const uploadResult = await findAndUpload(
logger,
features,
sarifPath,
pathStats,
checkoutPath,
analyses.CodeScanning,
category,
);
if (uploadResult !== undefined) {
uploadResults[analyses.AnalysisKind.CodeScanning] = uploadResult;
}

// If there are `.quality.sarif` files in `sarifPath`, then upload those to the code quality service.
const qualityUploadResult = await findAndUpload(
logger,
features,
sarifPath,
pathStats,
checkoutPath,
analyses.CodeQuality,
actionsUtil.fixCodeQualityCategory(logger, category),
);
if (qualityUploadResult !== undefined) {
uploadResults[analyses.AnalysisKind.CodeQuality] = qualityUploadResult;
}

return uploadResults;
}