Improve quoting of arguments for subprocess executions

* Add util function subprocess_util.convert_shell_cmd
* Apply function in
  - StdioLanguageServer (replacing use of quote_arg function)
  - RuntimeDependencyCollection (previously no quoting applied)
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-06-02 10:48:36 +02:00
1 parent 8a54795848
commit 5db677162c
4 files changed
+20 -28

No files matched your search

+1
View File
@@ -9,6 +9,7 @@ Status of the `main` branch. Changes prior to the next official version change w
at the Yarn-generated SDK.
- `SvelteLanguageServer`: Fix diagnostics requests for TypeScript/JavaScript files incorrectly being
processed by the Svelte LS instead of the TypeScript LS.
- Improve quoting of arguments in shell executions
* Dashboard:
- Make list of trusted hosts configurable, fixing host validation introduced in v1.5.2 allowing only
+3 -8
View File
@@ -10,7 +10,7 @@ from dataclasses import dataclass, replace
from typing import Any, cast
from solidlsp.ls_utils import FileUtils, PlatformUtils
from solidlsp.util.subprocess_util import subprocess_kwargs
from solidlsp.util import subprocess_util
log = logging.getLogger(__name__)
@@ -101,18 +101,13 @@ class RuntimeDependencyCollection:
@staticmethod
def _run_command(command: str | list[str], cwd: str) -> None:
kwargs = subprocess_kwargs()
kwargs = subprocess_util.subprocess_kwargs()
if not PlatformUtils.get_platform_id().is_windows():
import pwd
kwargs["user"] = pwd.getpwuid(os.getuid()).pw_name # type: ignore
is_windows = platform.system() == "Windows"
if not isinstance(command, str) and not is_windows:
# Since we are using the shell, we need to convert the command list to a single string
# on Linux/macOS
command = " ".join(command)
command = subprocess_util.convert_shell_cmd(command)
log.info("Running command %s in '%s'", f"'{command}'" if isinstance(command, str) else command, cwd)
completed_process = subprocess.run(
+6 -10
View File
@@ -2,7 +2,6 @@ import asyncio
import json
import logging
import os
import platform
import socket
import subprocess
import threading
@@ -33,7 +32,7 @@ from solidlsp.lsp_protocol_handler.server import (
make_request,
make_response,
)
from solidlsp.util.subprocess_util import quote_arg, subprocess_kwargs, terminate_process_tree_with_kill_fallback
from solidlsp.util import subprocess_util
log = logging.getLogger(__name__)
@@ -459,14 +458,9 @@ class StdioLanguageServer(LanguageServerInterface):
child_proc_env = os.environ.copy()
child_proc_env.update(self.process_launch_info.env)
cmd = self.process_launch_info.cmd
is_windows = platform.system() == "Windows"
if not isinstance(cmd, str) and not is_windows:
# Since we are using the shell, we need to convert the command list to a single string
# on Linux/macOS
cmd = " ".join(map(quote_arg, cmd))
cmd = subprocess_util.convert_shell_cmd(self.process_launch_info.cmd)
log.info("Starting language server process via command: %s", self.process_launch_info.cmd)
kwargs = subprocess_kwargs()
kwargs = subprocess_util.subprocess_kwargs()
kwargs["start_new_session"] = self.start_independent_lsp_process
self.process = subprocess.Popen(
cmd,
@@ -513,7 +507,9 @@ class StdioLanguageServer(LanguageServerInterface):
log.debug(f"Exception during graceful shutdown: {e}")
# Ignore errors here, we are proceeding to terminate anyway.
# terminate the process
terminate_process_tree_with_kill_fallback(self.process, terminate_timeout=timeout, process_name=f"LS[{self.language.value}]")
subprocess_util.terminate_process_tree_with_kill_fallback(
self.process, terminate_timeout=timeout, process_name=f"LS[{self.language.value}]"
)
finally:
self.process = None
+10 -10
View File
@@ -19,19 +19,19 @@ def subprocess_kwargs() -> dict:
return kwargs
def quote_arg(arg: str) -> str:
def convert_shell_cmd(cmd: str | list[str]) -> str | list[str]:
"""
Quotes a shell argument to prevent interpretation of metacharacters.
Converts a command (specified as a list or string) to a format supported by subprocess calls with shell=True on the current platform.
List format must be converted to string format on POSIX systems, quoting arguments appropriately,
while it can be used as-is on Windows.
Uses :func:`shlex.quote` on POSIX systems for proper escaping of all
shell-special characters. On Windows, wraps arguments containing spaces
in double quotes (Windows shell does not interpret single-quoted strings).
:param cmd: the command to convert, specified as a list of arguments
:return: a suitable representation of the command for subprocess calls on the current platform
"""
if platform.system() == "Windows":
if " " not in arg:
return arg
return f'"{arg}"'
return shlex.quote(arg)
if isinstance(cmd, list) and platform.system() != "Windows":
return " ".join(shlex.quote(arg) for arg in cmd)
else:
return cmd
def _signal_process_tree(process: subprocess.Popen[bytes], terminate: bool = True) -> None: