Skip to content

Commit bf9eb24

Browse files
Merge pull request #2370 from github/robertbrignull/undefined_codeflows
Avoid crashing when SARIF file contains invalid thread flow locations
2 parents 62f44c9 + 78c4cc1 commit bf9eb24

File tree

4 files changed

+89
-22
lines changed

4 files changed

+89
-22
lines changed

extensions/ql-vscode/src/variant-analysis/markdown-generation.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -275,17 +275,19 @@ function generateMarkdownForPathResults(
275275
threadFlow.highlightedRegion?.startLine,
276276
threadFlow.highlightedRegion?.endLine,
277277
);
278-
const codeSnippet = generateMarkdownForCodeSnippet(
279-
threadFlow.codeSnippet,
280-
language,
281-
threadFlow.highlightedRegion,
282-
);
283-
// Indent the snippet to fit with the numbered list.
284-
// The indentation is "n + 2" where the list number is an n-digit number.
285-
const codeSnippetIndented = codeSnippet.map((line) =>
286-
(" ".repeat(listNumber.toString().length + 2) + line).trimEnd(),
287-
);
288-
pathLines.push(`${listNumber}. ${link}`, ...codeSnippetIndented);
278+
pathLines.push(`${listNumber}. ${link}`);
279+
280+
if (threadFlow.codeSnippet) {
281+
const codeSnippet = generateMarkdownForCodeSnippet(
282+
threadFlow.codeSnippet,
283+
language,
284+
threadFlow.highlightedRegion,
285+
);
286+
const indentation = " ".repeat(listNumber.toString().length + 2);
287+
pathLines.push(
288+
...codeSnippet.map((line) => (indentation + line).trimEnd()),
289+
);
290+
}
289291
}
290292
lines.push(...buildExpandableMarkdownSection(title, pathLines));
291293
}

extensions/ql-vscode/src/variant-analysis/sarif-processing.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,23 @@ export function tryGetRule(
168168
return undefined;
169169
}
170170

171+
export function tryGetFilePath(
172+
physicalLocation: sarif.PhysicalLocation,
173+
): string | undefined {
174+
const filePath = physicalLocation.artifactLocation?.uri;
175+
// We expect the location uri value to be a relative file path, with no scheme.
176+
// We only need to support output from CodeQL here, so we can be quite strict,
177+
// even though the SARIF spec supports many more types of URI.
178+
if (
179+
filePath === undefined ||
180+
filePath === "" ||
181+
filePath.startsWith("file:")
182+
) {
183+
return undefined;
184+
}
185+
return filePath;
186+
}
187+
171188
function getCodeSnippet(
172189
contextRegion?: sarif.Region,
173190
region?: sarif.Region,
@@ -238,13 +255,13 @@ function getCodeFlows(
238255

239256
if (result.codeFlows) {
240257
for (const codeFlow of result.codeFlows) {
241-
const threadFlows = [];
258+
const threadFlows: ThreadFlow[] = [];
242259

243260
for (const threadFlow of codeFlow.threadFlows) {
244261
for (const threadFlowLocation of threadFlow.locations) {
245262
const physicalLocation =
246263
threadFlowLocation!.location!.physicalLocation!;
247-
const filePath = physicalLocation!.artifactLocation!.uri!;
264+
const filePath = tryGetFilePath(physicalLocation);
248265
const codeSnippet = getCodeSnippet(
249266
physicalLocation.contextRegion,
250267
physicalLocation.region,
@@ -253,14 +270,16 @@ function getCodeFlows(
253270
? getHighlightedRegion(physicalLocation.region)
254271
: undefined;
255272

256-
threadFlows.push({
257-
fileLink: {
258-
fileLinkPrefix,
259-
filePath,
260-
},
261-
codeSnippet,
262-
highlightedRegion,
263-
} as ThreadFlow);
273+
if (filePath !== undefined) {
274+
threadFlows.push({
275+
fileLink: {
276+
fileLinkPrefix,
277+
filePath,
278+
},
279+
codeSnippet,
280+
highlightedRegion,
281+
});
282+
}
264283
}
265284
}
266285

extensions/ql-vscode/src/variant-analysis/shared/analysis-result.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export interface CodeFlow {
4242

4343
export interface ThreadFlow {
4444
fileLink: FileLink;
45-
codeSnippet: CodeSnippet;
45+
codeSnippet?: CodeSnippet;
4646
highlightedRegion?: HighlightedRegion;
4747
message?: AnalysisMessage;
4848
}

extensions/ql-vscode/test/unit-tests/sarif-processing.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as sarif from "sarif";
22
import {
33
extractAnalysisAlerts,
4+
tryGetFilePath,
45
tryGetRule,
56
tryGetSeverity,
67
} from "../../src/variant-analysis/sarif-processing";
@@ -288,6 +289,51 @@ describe("SARIF processing", () => {
288289
});
289290
});
290291

292+
describe("tryGetFilePath", () => {
293+
it("should return value when uri is a file path", () => {
294+
const physicalLocation: sarif.PhysicalLocation = {
295+
artifactLocation: {
296+
uri: "foo/bar",
297+
},
298+
};
299+
expect(tryGetFilePath(physicalLocation)).toBe("foo/bar");
300+
});
301+
302+
it("should return undefined when uri has a file scheme", () => {
303+
const physicalLocation: sarif.PhysicalLocation = {
304+
artifactLocation: {
305+
uri: "file:/",
306+
},
307+
};
308+
expect(tryGetFilePath(physicalLocation)).toBe(undefined);
309+
});
310+
311+
it("should return undefined when uri is empty", () => {
312+
const physicalLocation: sarif.PhysicalLocation = {
313+
artifactLocation: {
314+
uri: "",
315+
},
316+
};
317+
expect(tryGetFilePath(physicalLocation)).toBe(undefined);
318+
});
319+
320+
it("should return undefined if artifact location uri is undefined", () => {
321+
const physicalLocation: sarif.PhysicalLocation = {
322+
artifactLocation: {
323+
uri: undefined,
324+
},
325+
};
326+
expect(tryGetFilePath(physicalLocation)).toBe(undefined);
327+
});
328+
329+
it("should return undefined if artifact location is undefined", () => {
330+
const physicalLocation: sarif.PhysicalLocation = {
331+
artifactLocation: undefined,
332+
};
333+
expect(tryGetFilePath(physicalLocation)).toBe(undefined);
334+
});
335+
});
336+
291337
describe("tryGetSeverity", () => {
292338
it("should return undefined if no rule set", () => {
293339
const result = {

0 commit comments

Comments
 (0)