mirror of
https://github.com/github/codeql-action.git
synced 2025-12-17 12:59:20 +08:00
Compare commits
4 Commits
copilot/up
...
kaspersv/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c8b134bbc | ||
|
|
d321539bd2 | ||
|
|
5e51e6e0db | ||
|
|
7329c8462a |
211
lib/analyze-action.js
generated
211
lib/analyze-action.js
generated
@@ -90161,29 +90161,6 @@ var persistInputs = function() {
|
||||
);
|
||||
core4.saveState(persistedInputsKey, JSON.stringify(inputEnvironmentVariables));
|
||||
};
|
||||
function getPullRequestBranches() {
|
||||
const pullRequest = github.context.payload.pull_request;
|
||||
if (pullRequest) {
|
||||
return {
|
||||
base: pullRequest.base.ref,
|
||||
// We use the head label instead of the head ref here, because the head
|
||||
// ref lacks owner information and by itself does not uniquely identify
|
||||
// the head branch (which may be in a forked repository).
|
||||
head: pullRequest.head.label
|
||||
};
|
||||
}
|
||||
const codeScanningRef = process.env.CODE_SCANNING_REF;
|
||||
const codeScanningBaseBranch = process.env.CODE_SCANNING_BASE_BRANCH;
|
||||
if (codeScanningRef && codeScanningBaseBranch) {
|
||||
return {
|
||||
base: codeScanningBaseBranch,
|
||||
// PR analysis under Default Setup analyzes the PR head commit instead of
|
||||
// the merge commit, so we can use the provided ref directly.
|
||||
head: codeScanningRef
|
||||
};
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
var qualityCategoryMapping = {
|
||||
"c#": "csharp",
|
||||
cpp: "c-cpp",
|
||||
@@ -91594,34 +91571,9 @@ var GitHubFeatureFlags = class {
|
||||
};
|
||||
|
||||
// src/diff-informed-analysis-utils.ts
|
||||
async function getDiffInformedAnalysisBranches(codeql, features, logger) {
|
||||
if (!await features.getValue("diff_informed_queries" /* DiffInformedQueries */, codeql)) {
|
||||
return void 0;
|
||||
}
|
||||
const gitHubVersion = await getGitHubVersion();
|
||||
if (gitHubVersion.type === 1 /* GHES */ && satisfiesGHESVersion(gitHubVersion.version, "<3.19", true)) {
|
||||
return void 0;
|
||||
}
|
||||
const branches = getPullRequestBranches();
|
||||
if (!branches) {
|
||||
logger.info(
|
||||
"Not performing diff-informed analysis because we are not analyzing a pull request."
|
||||
);
|
||||
}
|
||||
return branches;
|
||||
}
|
||||
function getDiffRangesJsonFilePath() {
|
||||
return path9.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
}
|
||||
function writeDiffRangesJsonFile(logger, ranges) {
|
||||
const jsonContents = JSON.stringify(ranges, null, 2);
|
||||
const jsonFilePath = getDiffRangesJsonFilePath();
|
||||
fs8.writeFileSync(jsonFilePath, jsonContents);
|
||||
logger.debug(
|
||||
`Wrote pr-diff-range JSON file to ${jsonFilePath}:
|
||||
${jsonContents}`
|
||||
);
|
||||
}
|
||||
function readDiffRangesJsonFile(logger) {
|
||||
const jsonFilePath = getDiffRangesJsonFilePath();
|
||||
if (!fs8.existsSync(jsonFilePath)) {
|
||||
@@ -91635,117 +91587,6 @@ ${jsonContents}`
|
||||
);
|
||||
return JSON.parse(jsonContents);
|
||||
}
|
||||
async function getPullRequestEditedDiffRanges(branches, logger) {
|
||||
const fileDiffs = await getFileDiffsWithBasehead(branches, logger);
|
||||
if (fileDiffs === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
if (fileDiffs.length >= 300) {
|
||||
logger.warning(
|
||||
`Cannot retrieve the full diff because there are too many (${fileDiffs.length}) changed files in the pull request.`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const results = [];
|
||||
for (const filediff of fileDiffs) {
|
||||
const diffRanges = getDiffRanges(filediff, logger);
|
||||
if (diffRanges === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
results.push(...diffRanges);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
async function getFileDiffsWithBasehead(branches, logger) {
|
||||
const repositoryNwo = getRepositoryNwoFromEnv(
|
||||
"CODE_SCANNING_REPOSITORY",
|
||||
"GITHUB_REPOSITORY"
|
||||
);
|
||||
const basehead = `${branches.base}...${branches.head}`;
|
||||
try {
|
||||
const response = await getApiClient().rest.repos.compareCommitsWithBasehead(
|
||||
{
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
basehead,
|
||||
per_page: 1
|
||||
}
|
||||
);
|
||||
logger.debug(
|
||||
`Response from compareCommitsWithBasehead(${basehead}):
|
||||
${JSON.stringify(response, null, 2)}`
|
||||
);
|
||||
return response.data.files;
|
||||
} catch (error2) {
|
||||
if (error2.status) {
|
||||
logger.warning(`Error retrieving diff ${basehead}: ${error2.message}`);
|
||||
logger.debug(
|
||||
`Error running compareCommitsWithBasehead(${basehead}):
|
||||
Request: ${JSON.stringify(error2.request, null, 2)}
|
||||
Error Response: ${JSON.stringify(error2.response, null, 2)}`
|
||||
);
|
||||
return void 0;
|
||||
} else {
|
||||
throw error2;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getDiffRanges(fileDiff, logger) {
|
||||
const filename = path9.join(getRequiredInput("checkout_path"), fileDiff.filename).replaceAll(path9.sep, "/");
|
||||
if (fileDiff.patch === void 0) {
|
||||
if (fileDiff.changes === 0) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
path: filename,
|
||||
startLine: 0,
|
||||
endLine: 0
|
||||
}
|
||||
];
|
||||
}
|
||||
let currentLine = 0;
|
||||
let additionRangeStartLine = void 0;
|
||||
const diffRanges = [];
|
||||
const diffLines = fileDiff.patch.split("\n");
|
||||
diffLines.push(" ");
|
||||
for (const diffLine of diffLines) {
|
||||
if (diffLine.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
if (diffLine.startsWith("+")) {
|
||||
if (additionRangeStartLine === void 0) {
|
||||
additionRangeStartLine = currentLine;
|
||||
}
|
||||
currentLine++;
|
||||
continue;
|
||||
}
|
||||
if (additionRangeStartLine !== void 0) {
|
||||
diffRanges.push({
|
||||
path: filename,
|
||||
startLine: additionRangeStartLine,
|
||||
endLine: currentLine - 1
|
||||
});
|
||||
additionRangeStartLine = void 0;
|
||||
}
|
||||
if (diffLine.startsWith("@@ ")) {
|
||||
const match = diffLine.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
||||
if (match === null) {
|
||||
logger.warning(
|
||||
`Cannot parse diff hunk header for ${fileDiff.filename}: ${diffLine}`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
currentLine = parseInt(match[1], 10);
|
||||
continue;
|
||||
}
|
||||
if (diffLine.startsWith(" ")) {
|
||||
currentLine++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return diffRanges;
|
||||
}
|
||||
|
||||
// src/trap-caching.ts
|
||||
var actionsCache2 = __toESM(require_cache3());
|
||||
@@ -93812,14 +93653,31 @@ async function finalizeDatabaseCreation(codeql, config, threadsFlag, memoryFlag,
|
||||
trap_import_duration_ms: Math.round(trapImportTime)
|
||||
};
|
||||
}
|
||||
async function setupDiffInformedQueryRun(branches, logger) {
|
||||
async function setupDiffInformedQueryRun(logger) {
|
||||
return await withGroupAsync(
|
||||
"Generating diff range extension pack",
|
||||
async () => {
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = readDiffRangesJsonFile(logger);
|
||||
} catch (e) {
|
||||
logger.debug(
|
||||
`Failed to read precomputed diff ranges: ${getErrorMessage(e)}`
|
||||
);
|
||||
diffRanges = void 0;
|
||||
}
|
||||
if (diffRanges === void 0) {
|
||||
logger.info(
|
||||
"No precomputed diff ranges found; skipping diff-informed analysis stage."
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const fileCount = new Set(
|
||||
diffRanges.filter((r) => r.path).map((r) => r.path)
|
||||
).size;
|
||||
logger.info(
|
||||
`Calculating diff ranges for ${branches.base}...${branches.head}`
|
||||
`Using precomputed diff ranges (${diffRanges.length} ranges across ${fileCount} files).`
|
||||
);
|
||||
const diffRanges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
const packDir = writeDiffRangeDataExtensionPack(logger, diffRanges);
|
||||
if (packDir === void 0) {
|
||||
logger.warning(
|
||||
@@ -93863,15 +93721,11 @@ extensions:
|
||||
checkPresence: false
|
||||
data:
|
||||
`;
|
||||
let data = ranges.map(
|
||||
(range) => (
|
||||
// Using yaml.dump() with `forceQuotes: true` ensures that all special
|
||||
// characters are escaped, and that the path is always rendered as a
|
||||
// quoted string on a single line.
|
||||
` - [${dump(range.path, { forceQuotes: true }).trim()}, ${range.startLine}, ${range.endLine}]
|
||||
`
|
||||
)
|
||||
).join("");
|
||||
let data = ranges.map((range) => {
|
||||
const filename = path16.join(getRequiredInput("checkout_path"), range.path).replaceAll(path16.sep, "/");
|
||||
return ` - [${dump(filename, { forceQuotes: true }).trim()}, ${range.startLine}, ${range.endLine}]
|
||||
`;
|
||||
}).join("");
|
||||
if (!data) {
|
||||
data = ' - ["", 0, 0]\n';
|
||||
}
|
||||
@@ -93882,7 +93736,6 @@ extensions:
|
||||
`Wrote pr-diff-range extension pack to ${extensionFilePath}:
|
||||
${extensionContents}`
|
||||
);
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
return diffRangeDir;
|
||||
}
|
||||
var defaultSuites = /* @__PURE__ */ new Set([
|
||||
@@ -96159,9 +96012,9 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!diffRanges?.length) {
|
||||
return sarif;
|
||||
}
|
||||
const checkoutPath = getRequiredInput("checkout_path");
|
||||
for (const run2 of sarif.runs) {
|
||||
if (run2.results) {
|
||||
const preAlertCount = run2.results.length;
|
||||
run2.results = run2.results.filter((result) => {
|
||||
const locations = [
|
||||
...(result.locations || []).map((loc) => loc.physicalLocation),
|
||||
@@ -96173,12 +96026,13 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!locationUri || locationStartLine === void 0) {
|
||||
return false;
|
||||
}
|
||||
const locationPath = path18.join(checkoutPath, locationUri).replaceAll(path18.sep, "/");
|
||||
return diffRanges.some(
|
||||
(range) => range.path === locationPath && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
(range) => range.path === locationUri && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
);
|
||||
});
|
||||
});
|
||||
const postAlertCount = run2.results.length;
|
||||
logger.info(`Filtered ${preAlertCount - postAlertCount} alerts based on diff range.`);
|
||||
}
|
||||
}
|
||||
return sarif;
|
||||
@@ -96379,12 +96233,7 @@ async function run() {
|
||||
getOptionalInput("ram") || process.env["CODEQL_RAM"],
|
||||
logger
|
||||
);
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger
|
||||
);
|
||||
const diffRangePackDir = branches ? await setupDiffInformedQueryRun(branches, logger) : void 0;
|
||||
const diffRangePackDir = await setupDiffInformedQueryRun(logger);
|
||||
await warnIfGoInstalledAfterInit(config, logger);
|
||||
await runAutobuildIfLegacyGoWorkflow(config, logger);
|
||||
dbCreationTimings = await runFinalize(
|
||||
|
||||
15
lib/init-action-post.js
generated
15
lib/init-action-post.js
generated
@@ -91192,8 +91192,8 @@ var require_primordials = __commonJS({
|
||||
ArrayPrototypeIndexOf(self2, el) {
|
||||
return self2.indexOf(el);
|
||||
},
|
||||
ArrayPrototypeJoin(self2, sep5) {
|
||||
return self2.join(sep5);
|
||||
ArrayPrototypeJoin(self2, sep4) {
|
||||
return self2.join(sep4);
|
||||
},
|
||||
ArrayPrototypeMap(self2, fn) {
|
||||
return self2.map(fn);
|
||||
@@ -103080,7 +103080,7 @@ var require_commonjs16 = __commonJS({
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(cwd = process.cwd(), pathImpl, sep5, { nocase, childrenCacheSize = 16 * 1024, fs: fs20 = defaultFS } = {}) {
|
||||
constructor(cwd = process.cwd(), pathImpl, sep4, { nocase, childrenCacheSize = 16 * 1024, fs: fs20 = defaultFS } = {}) {
|
||||
this.#fs = fsFromOption(fs20);
|
||||
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
||||
cwd = (0, node_url_1.fileURLToPath)(cwd);
|
||||
@@ -103091,7 +103091,7 @@ var require_commonjs16 = __commonJS({
|
||||
this.#resolveCache = new ResolveCache();
|
||||
this.#resolvePosixCache = new ResolveCache();
|
||||
this.#children = new ChildrenCache(childrenCacheSize);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep5);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep4);
|
||||
if (split.length === 1 && !split[0]) {
|
||||
split.pop();
|
||||
}
|
||||
@@ -133524,9 +133524,9 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!diffRanges?.length) {
|
||||
return sarif;
|
||||
}
|
||||
const checkoutPath = getRequiredInput("checkout_path");
|
||||
for (const run2 of sarif.runs) {
|
||||
if (run2.results) {
|
||||
const preAlertCount = run2.results.length;
|
||||
run2.results = run2.results.filter((result) => {
|
||||
const locations = [
|
||||
...(result.locations || []).map((loc) => loc.physicalLocation),
|
||||
@@ -133538,12 +133538,13 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!locationUri || locationStartLine === void 0) {
|
||||
return false;
|
||||
}
|
||||
const locationPath = path17.join(checkoutPath, locationUri).replaceAll(path17.sep, "/");
|
||||
return diffRanges.some(
|
||||
(range) => range.path === locationPath && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
(range) => range.path === locationUri && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
);
|
||||
});
|
||||
});
|
||||
const postAlertCount = run2.results.length;
|
||||
logger.info(`Filtered ${preAlertCount - postAlertCount} alerts based on diff range.`);
|
||||
}
|
||||
}
|
||||
return sarif;
|
||||
|
||||
969
lib/init-action.js
generated
969
lib/init-action.js
generated
File diff suppressed because it is too large
Load Diff
7
lib/upload-lib.js
generated
7
lib/upload-lib.js
generated
@@ -92962,9 +92962,9 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!diffRanges?.length) {
|
||||
return sarif;
|
||||
}
|
||||
const checkoutPath = getRequiredInput("checkout_path");
|
||||
for (const run of sarif.runs) {
|
||||
if (run.results) {
|
||||
const preAlertCount = run.results.length;
|
||||
run.results = run.results.filter((result) => {
|
||||
const locations = [
|
||||
...(result.locations || []).map((loc) => loc.physicalLocation),
|
||||
@@ -92976,12 +92976,13 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!locationUri || locationStartLine === void 0) {
|
||||
return false;
|
||||
}
|
||||
const locationPath = path14.join(checkoutPath, locationUri).replaceAll(path14.sep, "/");
|
||||
return diffRanges.some(
|
||||
(range) => range.path === locationPath && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
(range) => range.path === locationUri && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
);
|
||||
});
|
||||
});
|
||||
const postAlertCount = run.results.length;
|
||||
logger.info(`Filtered ${preAlertCount - postAlertCount} alerts based on diff range.`);
|
||||
}
|
||||
}
|
||||
return sarif;
|
||||
|
||||
7
lib/upload-sarif-action.js
generated
7
lib/upload-sarif-action.js
generated
@@ -93588,9 +93588,9 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!diffRanges?.length) {
|
||||
return sarif;
|
||||
}
|
||||
const checkoutPath = getRequiredInput("checkout_path");
|
||||
for (const run2 of sarif.runs) {
|
||||
if (run2.results) {
|
||||
const preAlertCount = run2.results.length;
|
||||
run2.results = run2.results.filter((result) => {
|
||||
const locations = [
|
||||
...(result.locations || []).map((loc) => loc.physicalLocation),
|
||||
@@ -93602,12 +93602,13 @@ function filterAlertsByDiffRange(logger, sarif) {
|
||||
if (!locationUri || locationStartLine === void 0) {
|
||||
return false;
|
||||
}
|
||||
const locationPath = path15.join(checkoutPath, locationUri).replaceAll(path15.sep, "/");
|
||||
return diffRanges.some(
|
||||
(range) => range.path === locationPath && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
(range) => range.path === locationUri && (range.startLine <= locationStartLine && range.endLine >= locationStartLine || range.startLine === 0 && range.endLine === 0)
|
||||
);
|
||||
});
|
||||
});
|
||||
const postAlertCount = run2.results.length;
|
||||
logger.info(`Filtered ${preAlertCount - postAlertCount} alerts based on diff range.`);
|
||||
}
|
||||
}
|
||||
return sarif;
|
||||
|
||||
@@ -30,7 +30,6 @@ import {
|
||||
DependencyCacheUploadStatusReport,
|
||||
uploadDependencyCaches,
|
||||
} from "./dependency-caching";
|
||||
import { getDiffInformedAnalysisBranches } from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, Features } from "./feature-flags";
|
||||
import { KnownLanguage } from "./languages";
|
||||
@@ -302,14 +301,8 @@ async function run() {
|
||||
logger,
|
||||
);
|
||||
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
const diffRangePackDir = branches
|
||||
? await setupDiffInformedQueryRun(branches, logger)
|
||||
: undefined;
|
||||
// Setup diff informed analysis if needed (based on whether init created the file)
|
||||
const diffRangePackDir = await setupDiffInformedQueryRun(logger);
|
||||
|
||||
await warnIfGoInstalledAfterInit(config, logger);
|
||||
await runAutobuildIfLegacyGoWorkflow(config, logger);
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as io from "@actions/io";
|
||||
import * as del from "del";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
import { getTemporaryDirectory, PullRequestBranches } from "./actions-util";
|
||||
import { getTemporaryDirectory, getRequiredInput } from "./actions-util";
|
||||
import * as analyses from "./analyses";
|
||||
import { setupCppAutobuild } from "./autobuild";
|
||||
import { type CodeQL } from "./codeql";
|
||||
@@ -15,8 +15,7 @@ import { getJavaTempDependencyDir } from "./dependency-caching";
|
||||
import { addDiagnostic, makeDiagnostic } from "./diagnostics";
|
||||
import {
|
||||
DiffThunkRange,
|
||||
writeDiffRangesJsonFile,
|
||||
getPullRequestEditedDiffRanges,
|
||||
readDiffRangesJsonFile,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { FeatureEnablement, Feature } from "./feature-flags";
|
||||
@@ -282,16 +281,36 @@ async function finalizeDatabaseCreation(
|
||||
* the diff range information, or `undefined` if the feature is disabled.
|
||||
*/
|
||||
export async function setupDiffInformedQueryRun(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
): Promise<string | undefined> {
|
||||
return await withGroupAsync(
|
||||
"Generating diff range extension pack",
|
||||
async () => {
|
||||
// Only use precomputed diff ranges; never recompute here.
|
||||
let diffRanges: DiffThunkRange[] | undefined;
|
||||
try {
|
||||
diffRanges = readDiffRangesJsonFile(logger);
|
||||
} catch (e) {
|
||||
logger.debug(
|
||||
`Failed to read precomputed diff ranges: ${util.getErrorMessage(e)}`,
|
||||
);
|
||||
diffRanges = undefined;
|
||||
}
|
||||
|
||||
if (diffRanges === undefined) {
|
||||
logger.info(
|
||||
"No precomputed diff ranges found; skipping diff-informed analysis stage.",
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fileCount = new Set(
|
||||
diffRanges.filter((r) => r.path).map((r) => r.path),
|
||||
).size;
|
||||
logger.info(
|
||||
`Calculating diff ranges for ${branches.base}...${branches.head}`,
|
||||
`Using precomputed diff ranges (${diffRanges.length} ranges across ${fileCount} files).`,
|
||||
);
|
||||
const diffRanges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
|
||||
const packDir = writeDiffRangeDataExtensionPack(logger, diffRanges);
|
||||
if (packDir === undefined) {
|
||||
logger.warning(
|
||||
@@ -366,14 +385,22 @@ extensions:
|
||||
`;
|
||||
|
||||
let data = ranges
|
||||
.map(
|
||||
(range) =>
|
||||
// Using yaml.dump() with `forceQuotes: true` ensures that all special
|
||||
// characters are escaped, and that the path is always rendered as a
|
||||
// quoted string on a single line.
|
||||
` - [${yaml.dump(range.path, { forceQuotes: true }).trim()}, ` +
|
||||
`${range.startLine}, ${range.endLine}]\n`,
|
||||
)
|
||||
.map((range) => {
|
||||
// Diff-informed queries expect the file path to be absolute. CodeQL always
|
||||
// uses forward slashes as the path separator, so on Windows we need to
|
||||
// replace any backslashes with forward slashes.
|
||||
const filename = path
|
||||
.join(getRequiredInput("checkout_path"), range.path)
|
||||
.replaceAll(path.sep, "/");
|
||||
|
||||
// Using yaml.dump() with `forceQuotes: true` ensures that all special
|
||||
// characters are escaped, and that the path is always rendered as a
|
||||
// quoted string on a single line.
|
||||
return (
|
||||
` - [${yaml.dump(filename, { forceQuotes: true }).trim()}, ` +
|
||||
`${range.startLine}, ${range.endLine}]\n`
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
if (!data) {
|
||||
// Ensure that the data extension is not empty, so that a pull request with
|
||||
@@ -388,10 +415,6 @@ extensions:
|
||||
`Wrote pr-diff-range extension pack to ${extensionFilePath}:\n${extensionContents}`,
|
||||
);
|
||||
|
||||
// Write the diff ranges to a JSON file, for action-side alert filtering by the
|
||||
// upload-lib module.
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
|
||||
return diffRangeDir;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,10 +188,6 @@ test(
|
||||
);
|
||||
|
||||
function runGetDiffRanges(changes: number, patch: string[] | undefined): any {
|
||||
sinon
|
||||
.stub(actionsUtil, "getRequiredInput")
|
||||
.withArgs("checkout_path")
|
||||
.returns("/checkout/path");
|
||||
return exportedForTesting.getDiffRanges(
|
||||
{
|
||||
filename: "test.txt",
|
||||
@@ -211,7 +207,7 @@ test("getDiffRanges: file diff too large", async (t) => {
|
||||
const diffRanges = runGetDiffRanges(1000000, undefined);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 0,
|
||||
endLine: 0,
|
||||
},
|
||||
@@ -232,7 +228,7 @@ test("getDiffRanges: diff thunk with single addition range", async (t) => {
|
||||
]);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 53,
|
||||
endLine: 54,
|
||||
},
|
||||
@@ -268,7 +264,7 @@ test("getDiffRanges: diff thunk with single update range", async (t) => {
|
||||
]);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 53,
|
||||
endLine: 53,
|
||||
},
|
||||
@@ -290,12 +286,12 @@ test("getDiffRanges: diff thunk with addition ranges", async (t) => {
|
||||
]);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 53,
|
||||
endLine: 53,
|
||||
},
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 55,
|
||||
endLine: 55,
|
||||
},
|
||||
@@ -322,12 +318,12 @@ test("getDiffRanges: diff thunk with mixed ranges", async (t) => {
|
||||
]);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 54,
|
||||
endLine: 54,
|
||||
},
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 57,
|
||||
endLine: 58,
|
||||
},
|
||||
@@ -357,12 +353,12 @@ test("getDiffRanges: multiple diff thunks", async (t) => {
|
||||
]);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 53,
|
||||
endLine: 54,
|
||||
},
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 153,
|
||||
endLine: 154,
|
||||
},
|
||||
@@ -373,7 +369,7 @@ test("getDiffRanges: no diff context lines", async (t) => {
|
||||
const diffRanges = runGetDiffRanges(2, ["@@ -30 +50,2 @@", "+1", "+2"]);
|
||||
t.deepEqual(diffRanges, [
|
||||
{
|
||||
path: "/checkout/path/test.txt",
|
||||
path: "test.txt",
|
||||
startLine: 50,
|
||||
endLine: 51,
|
||||
},
|
||||
|
||||
@@ -191,12 +191,7 @@ function getDiffRanges(
|
||||
fileDiff: FileDiff,
|
||||
logger: Logger,
|
||||
): DiffThunkRange[] | undefined {
|
||||
// Diff-informed queries expect the file path to be absolute. CodeQL always
|
||||
// uses forward slashes as the path separator, so on Windows we need to
|
||||
// replace any backslashes with forward slashes.
|
||||
const filename = path
|
||||
.join(actionsUtil.getRequiredInput("checkout_path"), fileDiff.filename)
|
||||
.replaceAll(path.sep, "/");
|
||||
const filename = fileDiff.filename;
|
||||
|
||||
if (fileDiff.patch === undefined) {
|
||||
if (fileDiff.changes === 0) {
|
||||
|
||||
@@ -34,6 +34,11 @@ import {
|
||||
logUnwrittenDiagnostics,
|
||||
makeDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import {
|
||||
getPullRequestEditedDiffRanges,
|
||||
writeDiffRangesJsonFile,
|
||||
getDiffInformedAnalysisBranches,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, Features } from "./feature-flags";
|
||||
import { loadPropertiesFromApi } from "./feature-flags/properties";
|
||||
@@ -46,7 +51,7 @@ import {
|
||||
runDatabaseInitCluster,
|
||||
} from "./init";
|
||||
import { KnownLanguage } from "./languages";
|
||||
import { getActionsLogger, Logger } from "./logging";
|
||||
import { getActionsLogger, Logger, withGroupAsync } from "./logging";
|
||||
import {
|
||||
downloadOverlayBaseDatabaseFromCache,
|
||||
OverlayBaseDatabaseDownloadStats,
|
||||
@@ -358,6 +363,7 @@ async function run() {
|
||||
});
|
||||
|
||||
await checkInstallPython311(config.languages, codeql);
|
||||
await computeAndPersistDiffRanges(codeql, features, logger);
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
core.setFailed(error.message);
|
||||
@@ -770,6 +776,43 @@ async function run() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and persist diff ranges when diff-informed analysis
|
||||
* is enabled (feature flag + PR context). This writes the standard pr-diff-range.json
|
||||
* file for later reuse in the analyze step. Failures are logged but non-fatal.
|
||||
*/
|
||||
async function computeAndPersistDiffRanges(
|
||||
codeql: CodeQL,
|
||||
features: Features,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await withGroupAsync("Compute PR diff ranges", async () => {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
if (!branches) {
|
||||
return;
|
||||
}
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return;
|
||||
}
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
|
||||
logger.info(
|
||||
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute and persist PR diff ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getTrapCachingEnabled(): boolean {
|
||||
// If the workflow specified something always respect that
|
||||
const trapCaching = getOptionalInput("trap-caching");
|
||||
|
||||
@@ -1140,10 +1140,9 @@ function filterAlertsByDiffRange(logger: Logger, sarif: SarifFile): SarifFile {
|
||||
return sarif;
|
||||
}
|
||||
|
||||
const checkoutPath = actionsUtil.getRequiredInput("checkout_path");
|
||||
|
||||
for (const run of sarif.runs) {
|
||||
if (run.results) {
|
||||
const preAlertCount = run.results.length;
|
||||
run.results = run.results.filter((result) => {
|
||||
const locations = [
|
||||
...(result.locations || []).map((loc) => loc.physicalLocation),
|
||||
@@ -1156,11 +1155,6 @@ function filterAlertsByDiffRange(logger: Logger, sarif: SarifFile): SarifFile {
|
||||
if (!locationUri || locationStartLine === undefined) {
|
||||
return false;
|
||||
}
|
||||
// CodeQL always uses forward slashes as the path separator, so on Windows we
|
||||
// need to replace any backslashes with forward slashes.
|
||||
const locationPath = path
|
||||
.join(checkoutPath, locationUri)
|
||||
.replaceAll(path.sep, "/");
|
||||
// Alert filtering here replicates the same behavior as the restrictAlertsTo
|
||||
// extensible predicate in CodeQL. See the restrictAlertsTo documentation
|
||||
// https://codeql.github.com/codeql-standard-libraries/csharp/codeql/util/AlertFiltering.qll/predicate.AlertFiltering$restrictAlertsTo.3.html
|
||||
@@ -1168,13 +1162,16 @@ function filterAlertsByDiffRange(logger: Logger, sarif: SarifFile): SarifFile {
|
||||
// of an alert location.
|
||||
return diffRanges.some(
|
||||
(range) =>
|
||||
range.path === locationPath &&
|
||||
range.path === locationUri &&
|
||||
((range.startLine <= locationStartLine &&
|
||||
range.endLine >= locationStartLine) ||
|
||||
(range.startLine === 0 && range.endLine === 0)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const postAlertCount = run.results.length;
|
||||
logger.info(`Filtered ${preAlertCount - postAlertCount} alerts based on diff range.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user