Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions libs/python/computer/computer/providers/lume_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import urllib.parse
from typing import Any, Dict, List, Optional

from computer.utils import safe_join

# Setup logging
logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -59,7 +61,7 @@ def lume_api_get(
# --max-time: Maximum time for the whole operation (20 seconds)
# -f: Fail silently (no output at all) on server errors
# Add single quotes around URL to ensure special characters are handled correctly
cmd = ["curl", "--connect-timeout", "15", "--max-time", "20", "-s", "-f", f"'{api_url}'"]
cmd = ["curl", "--connect-timeout", "15", "--max-time", "20", "-s", "-f", api_url]

# For logging and display, show the properly escaped URL
display_cmd = ["curl", "--connect-timeout", "15", "--max-time", "20", "-s", "-f", api_url]
Expand All @@ -71,7 +73,7 @@ def lume_api_get(
# Execute the command - for execution we need to use shell=True to handle URLs with special characters
try:
# Use a single string with shell=True for proper URL handling
shell_cmd = " ".join(cmd)
shell_cmd = safe_join(cmd)
result = subprocess.run(shell_cmd, shell=True, capture_output=True, text=True)

# Handle curl exit codes
Expand Down Expand Up @@ -514,7 +516,7 @@ def lume_api_delete(
"-s",
"-X",
"DELETE",
f"'{api_url}'",
api_url,
]

# For logging and display, show the properly escaped URL
Expand All @@ -537,7 +539,7 @@ def lume_api_delete(
# Execute the command - for execution we need to use shell=True to handle URLs with special characters
try:
# Use a single string with shell=True for proper URL handling
shell_cmd = " ".join(cmd)
shell_cmd = safe_join(cmd)
result = subprocess.run(shell_cmd, shell=True, capture_output=True, text=True)

# Handle curl exit codes
Expand Down
25 changes: 25 additions & 0 deletions libs/python/computer/computer/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import base64
import io
import os
import shlex
from typing import Any, Dict, Optional, Tuple

import mslex
from PIL import Image, ImageDraw


Expand Down Expand Up @@ -104,3 +107,25 @@ def parse_vm_info(vm_info: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""Parse VM info from pylume response."""
if not vm_info:
return None


def safe_join(argv: list[str]) -> str:
"""
Return a platform-correct string that safely quotes `argv` for shell execution.

- On POSIX: uses `shlex.join`.
- On Windows: uses `shlex.join`.

Args:
argv: iterable of argument strings (will be coerced to str).

Returns:
A safely quoted command-line string appropriate for the current platform that protects against
shell injection vulnerabilities.
"""
if os.name == "nt":
# On Windows, use mslex for proper quoting
return mslex.join(argv)
else:
# On POSIX systems, use shlex
return shlex.join(argv)
5 changes: 3 additions & 2 deletions libs/python/computer/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ dependencies = [
"websockets>=12.0",
"aiohttp>=3.9.0",
"cua-core>=0.1.0,<0.2.0",
"pydantic>=2.11.1"
"pydantic>=2.11.1",
"mslex>=1.3.0",
]
requires-python = ">=3.12"

Expand Down Expand Up @@ -47,4 +48,4 @@ source-includes = ["tests/", "README.md", "LICENSE"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
python_files = "test_*.py"
python_files = "test_*.py"
17 changes: 14 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading