Skip to content

v0.8#190

Merged
selfint merged 43 commits intomainfrom
v0.8
Nov 8, 2025
Merged

v0.8#190
selfint merged 43 commits intomainfrom
v0.8

Conversation

@selfint
Copy link
Copy Markdown
Owner

@selfint selfint commented Oct 31, 2025

  • update all dependencies to latest versions
  • update CHANGELOG.md
  • update package version

onData?.(d.toString())
logger.log(`Building parser ${parserName}`);
const buildResult = await runCmd(
`${npm} exec --yes --loglevel silly --prefix ${parsersDir} node-gyp rebuild --target=${process.versions.electron} --dist-url=https://electronjs.org/headers --runtime=electron`,

Check warning

Code scanning / CodeQL

Unsafe shell command constructed from library input Medium

This string concatenation which depends on
library input
is later used in a
shell command
.

Copilot Autofix

AI 5 months ago

General fix:
Avoid passing any untrusted (or derived) data directly into a shell command string. Instead, use an argument array and a shell-less invocation with execFile, which does not invoke the shell and passes arguments as-is, eliminating the chance of command injection or accidental breakage due to whitespace or special characters.

Detailed fix:

  • Refactor the construction and invocation of the npm/node-gyp build command in downloadAndBuildParser so that it does not use string interpolation to produce a shell command string.
  • Instead, build an array of arguments and call execFile (or its promisified version) with shell: false.
  • Update the runCmd function so it can call execFile instead of exec when given arguments as an array.
    (Alternatively, split the function, but the cleanest way is to use argument array + execFile.)
  • Pass path-like variables (such as ${parsersDir}) as arguments, not as part of a single command string.
  • Add any required imports (e.g., execFile from child_process).
  • Change the code path in downloadAndBuildParser (and the call to runCmd) to pass an array of arguments to ensure correct, injection-safe execution.

File/region/line specifics:

  • Edit src/Installer.ts:
    • Refactor the command creation at line 127.
    • Update runCmd to use execFile (or to differentiate between string/array commands).
    • Add any required imports.

Suggested changeset 1
src/Installer.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/Installer.ts b/src/Installer.ts
--- a/src/Installer.ts
+++ b/src/Installer.ts
@@ -2,7 +2,7 @@
 import * as path from "path";
 import * as tar from "tar";
 import * as vscode from "vscode";
-import { ExecException, ExecOptions, exec } from "child_process";
+import { ExecException, ExecOptions, exec, execFile } from "child_process";
 import { Result, err, ok } from "./result";
 import { existsSync, rmSync } from "fs";
 import type { Language } from "tree-sitter";
@@ -124,7 +124,20 @@
     // if it fails, try to build it
     logger.log(`Building parser ${parserName}`);
     const buildResult = await runCmd(
-        `${npm} exec --yes --loglevel silly --prefix ${parsersDir} node-gyp rebuild --target=${process.versions.electron} --dist-url=https://electronjs.org/headers --runtime=electron`,
+        [
+            npm,
+            "exec",
+            "--yes",
+            "--loglevel",
+            "silly",
+            "--prefix",
+            parsersDir,
+            "node-gyp",
+            "rebuild",
+            `--target=${process.versions.electron}`,
+            "--dist-url=https://electronjs.org/headers",
+            "--runtime=electron"
+        ],
         { cwd: parserDir },
         (d) => onData?.(d.toString())
     );
@@ -146,22 +159,39 @@
 }
 
 async function runCmd(
-    cmd: string,
+    cmd: string | string[],
     options: ExecOptions = {},
     onData?: (data: Buffer) => void
 ): Promise<Result<string, [ExecException, string[]]>> {
     const logger = getLogger();
-    logger.log(`Running command: ${cmd}`);
+    logger.log(
+        `Running command: ${
+            Array.isArray(cmd) ? cmd.map(x => JSON.stringify(x)).join(' ') : cmd
+        }`
+    );
 
     const logs: string[] = [];
     return await new Promise((resolve) => {
-        const proc = exec(cmd, options, (error, stdout: string | Buffer, _stderr) => {
-            if (error !== null) {
-                resolve(err([error, logs]));
-            } else {
-                resolve(ok(stdout.toString()));
-            }
-        });
+        let proc;
+        if (Array.isArray(cmd)) {
+            // The first element is the file, the rest are the arguments
+            const [file, ...args] = cmd;
+            proc = execFile(file, args, options, (error, stdout: string | Buffer, _stderr) => {
+                if (error !== null) {
+                    resolve(err([error, logs]));
+                } else {
+                    resolve(ok(stdout.toString()));
+                }
+            });
+        } else {
+            proc = exec(cmd, options, (error, stdout: string | Buffer, _stderr) => {
+                if (error !== null) {
+                    resolve(err([error, logs]));
+                } else {
+                    resolve(ok(stdout.toString()));
+                }
+            });
+        }
 
         if (onData !== undefined) {
             proc.stdout?.on("data", onData);
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
@selfint selfint merged commit a04cf9a into main Nov 8, 2025
13 checks passed
@selfint selfint deleted the v0.8 branch November 8, 2025 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants