Skip to content

Commit f55f46f

Browse files
committed
Markdown rendering: Display paths
1 parent 5ee2f0e commit f55f46f

3 files changed

Lines changed: 282 additions & 18 deletions

File tree

extensions/ql-vscode/src/remote-queries/remote-queries-markdown-generation.ts

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ function generateMarkdownForInterpretedResult(interpretedResult: AnalysisAlert,
8989
...generateMarkdownForCodeSnippet(codeSnippet, language, highlightedRegion),
9090
);
9191
}
92-
const alertMessage = buildMarkdownAlertMessage(interpretedResult);
93-
lines.push(alertMessage);
92+
const alertMessageLines = buildMarkdownAlertMessage(interpretedResult, language);
93+
lines.push(...alertMessageLines);
9494

9595
// Padding between results
9696
lines.push(
@@ -142,22 +142,67 @@ function highlightCodeLines(
142142
return `${partiallyHighlightedLine.plainSection1}<strong>${partiallyHighlightedLine.highlightedSection}</strong>${partiallyHighlightedLine.plainSection2}`;
143143
}
144144

145-
function buildMarkdownAlertMessage(interpretedResult: AnalysisAlert): string {
145+
function buildMarkdownAlertMessage(
146+
interpretedResult: AnalysisAlert,
147+
language: string
148+
): string[] {
149+
const hasPathResults = interpretedResult.codeFlows.length > 0;
150+
if (hasPathResults) {
151+
// For path-problem queries, the "alert message" is an expandable section containing the path results.
152+
return buildMarkdownPathResults(interpretedResult, language);
153+
} else {
154+
let alertMessage = '';
155+
// For regular problem queries (no paths), the alert message is just a message
156+
// containing a link to the affected file.
157+
for (const token of interpretedResult.message.tokens) {
158+
if (token.t === 'text') {
159+
alertMessage += token.text;
160+
} else if (token.t === 'location') {
161+
alertMessage += createMarkdownRemoteFileRef(
162+
token.location.fileLink,
163+
token.location.highlightedRegion?.startLine,
164+
token.location.highlightedRegion?.endLine,
165+
token.text
166+
);
167+
}
168+
}
169+
// Italicize the alert message
170+
return [`*${alertMessage}*`];
171+
}
172+
}
173+
174+
function buildMarkdownPathResults(
175+
interpretedResult: AnalysisAlert,
176+
language: string
177+
): MarkdownFile {
146178
let alertMessage = '';
147179
for (const token of interpretedResult.message.tokens) {
148-
if (token.t === 'text') {
149-
alertMessage += token.text;
150-
} else if (token.t === 'location') {
151-
alertMessage += createMarkdownRemoteFileRef(
152-
token.location.fileLink,
153-
token.location.highlightedRegion?.startLine,
154-
token.location.highlightedRegion?.endLine,
155-
token.text,
180+
alertMessage += token.text;
181+
}
182+
const pathLines: MarkdownFile = [];
183+
pathLines.push('#### Paths', '');
184+
for (const codeFlow of interpretedResult.codeFlows) {
185+
const stepCount = codeFlow.threadFlows.length;
186+
pathLines.push(`Path with ${stepCount} steps`);
187+
let index = 1;
188+
for (const threadFlow of codeFlow.threadFlows) {
189+
const link = createMarkdownRemoteFileRef(
190+
threadFlow.fileLink,
191+
threadFlow.highlightedRegion?.startLine,
192+
threadFlow.highlightedRegion?.endLine
193+
);
194+
const codeSnippet = generateMarkdownForCodeSnippet(
195+
threadFlow.codeSnippet,
196+
language,
197+
threadFlow.highlightedRegion
156198
);
199+
// Indent the snippet to fit with the numbered list.
200+
const codeSnippetIndented = codeSnippet.map((line) => ` ${line}`);
201+
pathLines.push(`${index}. ${link}`, ...codeSnippetIndented);
202+
index++;
157203
}
158204
}
159-
// Italicize the alert message
160-
return `*${alertMessage}*`;
205+
return buildExpandableMarkdownSection(`<i>${alertMessage}</i>`, pathLines);
161206
}
162207

163208
/**

extensions/ql-vscode/test/pure-tests/remote-queries/markdown-generation/data/interpreted-results/path-problem/results-repo1.md

Lines changed: 147 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,54 @@
88
}
99
</code></pre>
1010

11-
*This shell command depends on an uncontrolled [absolute path](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4).*
11+
<details>
12+
<summary><i>This shell command depends on an uncontrolled absolute path.</i></summary>
13+
14+
#### Paths
15+
16+
Path with 5 steps
17+
1. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
18+
<pre><code class="javascript"> path = require("path");
19+
function cleanupTemp() {
20+
let cmd = "rm -rf " + path.join(<strong>__dirname</strong>, "temp");
21+
cp.execSync(cmd); // BAD
22+
}
23+
</code></pre>
24+
25+
2. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
26+
<pre><code class="javascript"> path = require("path");
27+
function cleanupTemp() {
28+
let cmd = "rm -rf " + <strong>path.join(__dirname, "temp")</strong>;
29+
cp.execSync(cmd); // BAD
30+
}
31+
</code></pre>
32+
33+
3. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
34+
<pre><code class="javascript"> path = require("path");
35+
function cleanupTemp() {
36+
let cmd = <strong>"rm -rf " + path.join(__dirname, "temp")</strong>;
37+
cp.execSync(cmd); // BAD
38+
}
39+
</code></pre>
40+
41+
4. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
42+
<pre><code class="javascript"> path = require("path");
43+
function cleanupTemp() {
44+
let <strong>cmd = "rm -rf " + path.join(__dirname, "temp")</strong>;
45+
cp.execSync(cmd); // BAD
46+
}
47+
</code></pre>
48+
49+
5. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L5-L5)
50+
<pre><code class="javascript">function cleanupTemp() {
51+
let cmd = "rm -rf " + path.join(__dirname, "temp");
52+
cp.execSync(<strong>cmd</strong>); // BAD
53+
}
54+
</code></pre>
55+
56+
57+
</details>
58+
1259

1360
----------------------------------------
1461

@@ -21,7 +68,39 @@
2168
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
2269
</code></pre>
2370

24-
*This shell command depends on an uncontrolled [absolute path](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6).*
71+
<details>
72+
<summary><i>This shell command depends on an uncontrolled absolute path.</i></summary>
73+
74+
#### Paths
75+
76+
Path with 3 steps
77+
1. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6)
78+
<pre><code class="javascript">(function() {
79+
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
80+
cp.execSync('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // BAD
81+
82+
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
83+
</code></pre>
84+
85+
2. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6)
86+
<pre><code class="javascript">(function() {
87+
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
88+
cp.execSync('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // BAD
89+
90+
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
91+
</code></pre>
92+
93+
3. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6)
94+
<pre><code class="javascript">(function() {
95+
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
96+
cp.execSync(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // BAD
97+
98+
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
99+
</code></pre>
100+
101+
102+
</details>
103+
25104

26105
----------------------------------------
27106

@@ -34,7 +113,39 @@
34113

35114
</code></pre>
36115

37-
*This shell command depends on an uncontrolled [absolute path](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8).*
116+
<details>
117+
<summary><i>This shell command depends on an uncontrolled absolute path.</i></summary>
118+
119+
#### Paths
120+
121+
Path with 3 steps
122+
1. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8)
123+
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
124+
125+
execa.shell('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // NOT OK
126+
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
127+
128+
</code></pre>
129+
130+
2. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8)
131+
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
132+
133+
execa.shell('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // NOT OK
134+
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
135+
136+
</code></pre>
137+
138+
3. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8)
139+
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
140+
141+
execa.shell(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // NOT OK
142+
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
143+
144+
</code></pre>
145+
146+
147+
</details>
148+
38149

39150
----------------------------------------
40151

@@ -47,6 +158,38 @@
47158
const safe = "\"" + path.join(__dirname, "temp") + "\"";
48159
</code></pre>
49160

50-
*This shell command depends on an uncontrolled [absolute path](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9).*
161+
<details>
162+
<summary><i>This shell command depends on an uncontrolled absolute path.</i></summary>
163+
164+
#### Paths
165+
166+
Path with 3 steps
167+
1. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9)
168+
<pre><code class="javascript">
169+
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
170+
execa.shellSync('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // NOT OK
171+
172+
const safe = "\"" + path.join(__dirname, "temp") + "\"";
173+
</code></pre>
174+
175+
2. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9)
176+
<pre><code class="javascript">
177+
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
178+
execa.shellSync('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // NOT OK
179+
180+
const safe = "\"" + path.join(__dirname, "temp") + "\"";
181+
</code></pre>
182+
183+
3. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9)
184+
<pre><code class="javascript">
185+
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
186+
execa.shellSync(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // NOT OK
187+
188+
const safe = "\"" + path.join(__dirname, "temp") + "\"";
189+
</code></pre>
190+
191+
192+
</details>
193+
51194

52195
----------------------------------------

extensions/ql-vscode/test/pure-tests/remote-queries/markdown-generation/data/interpreted-results/path-problem/results-repo2.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,82 @@
99
}
1010
</code></pre>
1111

12-
*This shell command depends on an uncontrolled [absolute path](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L39-L39).*
12+
<details>
13+
<summary><i>This shell command depends on an uncontrolled absolute path.</i></summary>
14+
15+
#### Paths
16+
17+
Path with 7 steps
18+
1. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L39-L39)
19+
<pre><code class="javascript">
20+
const meteorLocalFolder = '.meteor';
21+
const meteorPath = <strong>path.resolve(rootPath, meteorLocalFolder)</strong>;
22+
23+
module.exports = {
24+
</code></pre>
25+
26+
2. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L39-L39)
27+
<pre><code class="javascript">
28+
const meteorLocalFolder = '.meteor';
29+
const <strong>meteorPath = path.resolve(rootPath, meteorLocalFolder)</strong>;
30+
31+
module.exports = {
32+
</code></pre>
33+
34+
3. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L44-L44)
35+
<pre><code class="javascript"> METEOR_LATEST_VERSION,
36+
extractPath: rootPath,
37+
<strong>meteorPath</strong>,
38+
release: process.env.INSTALL_METEOR_VERSION || METEOR_LATEST_VERSION,
39+
rootPath,
40+
</code></pre>
41+
42+
4. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L12-L12)
43+
<pre><code class="javascript">const os = require('os');
44+
const {
45+
<strong>meteorPath</strong>,
46+
release,
47+
startedPath,
48+
</code></pre>
49+
50+
5. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L11-L23)
51+
<pre><code class="javascript">const tmp = require('tmp');
52+
const os = require('os');
53+
const <strong>{</strong>
54+
<strong> meteorPath,</strong>
55+
<strong> release,</strong>
56+
<strong> startedPath,</strong>
57+
<strong> extractPath,</strong>
58+
<strong> isWindows,</strong>
59+
<strong> rootPath,</strong>
60+
<strong> sudoUser,</strong>
61+
<strong> isSudo,</strong>
62+
<strong> isMac,</strong>
63+
<strong> METEOR_LATEST_VERSION,</strong>
64+
<strong> shouldSetupExecPath,</strong>
65+
<strong>} = require('./config.js')</strong>;
66+
const { uninstall } = require('./uninstall');
67+
const {
68+
</code></pre>
69+
70+
6. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
71+
<pre><code class="javascript"> if (isWindows()) {
72+
//set for the current session and beyond
73+
child_process.execSync(`setx path "${<strong>meteorPath</strong>}/;%path%`);
74+
return;
75+
}
76+
</code></pre>
77+
78+
7. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
79+
<pre><code class="javascript"> if (isWindows()) {
80+
//set for the current session and beyond
81+
child_process.execSync(<strong>`setx path "${meteorPath}/;%path%`</strong>);
82+
return;
83+
}
84+
</code></pre>
85+
86+
87+
</details>
88+
1389

1490
----------------------------------------

0 commit comments

Comments
 (0)