@@ -14,6 +14,7 @@ import * as api from "./api-client";
1414import { getGitHubVersion, wrapApiConfigurationError } from "./api-client";
1515import { CodeQL, getCodeQL } from "./codeql";
1616import { getConfig } from "./config-utils";
17+ import { readDiffRangesJsonFile } from "./diff-filtering-utils";
1718import { EnvVar } from "./environment";
1819import { FeatureEnablement } from "./feature-flags";
1920import * as fingerprints from "./fingerprints";
@@ -578,6 +579,7 @@ export async function uploadFiles(
578579 features,
579580 logger,
580581 );
582+ sarif = filterAlertsByDiffRange(logger, sarif);
581583 sarif = await fingerprints.addFingerprints(sarif, checkoutPath, logger);
582584
583585 const analysisKey = await api.getAnalysisKey();
@@ -848,3 +850,50 @@ export class InvalidSarifUploadError extends Error {
848850 super(message);
849851 }
850852}
853+
854+ function filterAlertsByDiffRange(logger: Logger, sarif: SarifFile): SarifFile {
855+ const diffRanges = readDiffRangesJsonFile(logger);
856+ if (!diffRanges?.length) {
857+ return sarif;
858+ }
859+
860+ const checkoutPath = actionsUtil.getRequiredInput("checkout_path");
861+
862+ for (const run of sarif.runs) {
863+ if (run.results) {
864+ run.results = run.results.filter((result) => {
865+ const locations = [
866+ ...(result.locations || []).map((loc) => loc.physicalLocation),
867+ ...(result.relatedLocations || []).map((loc) => loc.physicalLocation),
868+ ];
869+
870+ return locations.some((physicalLocation) => {
871+ const locationUri = physicalLocation?.artifactLocation?.uri;
872+ const locationStartLine = physicalLocation?.region?.startLine;
873+ if (!locationUri || locationStartLine === undefined) {
874+ return false;
875+ }
876+ // CodeQL always uses forward slashes as the path separator, so on Windows we
877+ // need to replace any backslashes with forward slashes.
878+ const locationPath = path
879+ .join(checkoutPath, locationUri)
880+ .replaceAll(path.sep, "/");
881+ // Alert filtering here replicates the same behavior as the restrictAlertsTo
882+ // extensible predicate in CodeQL. See the restrictAlertsTo documentation
883+ // https://codeql.github.com/codeql-standard-libraries/csharp/codeql/util/AlertFiltering.qll/predicate.AlertFiltering$restrictAlertsTo.3.html
884+ // for more details, such as why the filtering applies only to the first line
885+ // of an alert location.
886+ return diffRanges.some(
887+ (range) =>
888+ range.path === locationPath &&
889+ ((range.startLine <= locationStartLine &&
890+ range.endLine >= locationStartLine) ||
891+ (range.startLine === 0 && range.endLine === 0)),
892+ );
893+ });
894+ });
895+ }
896+ }
897+
898+ return sarif;
899+ }
0 commit comments