Skip to content

fix(server): use shutil.which to resolve npm for Windows compatibility#3340

Open
deacon-mp wants to merge 2 commits into
masterfrom
fix/npm-windows-compat-shutil-which
Open

fix(server): use shutil.which to resolve npm for Windows compatibility#3340
deacon-mp wants to merge 2 commits into
masterfrom
fix/npm-windows-compat-shutil-which

Conversation

@deacon-mp
Copy link
Copy Markdown
Contributor

Summary

  • Fixes Windows compatibility for --build and --uidev flags where subprocess.run(["npm", ...]) fails because npm is a batch script (npm.cmd) on Windows
  • Uses shutil.which("npm") to resolve the full path instead of adding shell=True (which is a security concern per Bandit B602)
  • Adds _resolve_npm() helper with a clear error message if npm is not installed
  • Supersedes PR fix(server): add shell=True to npm subprocess calls for Windows compa… #3194 which proposed shell=True

Test plan

  • Verify --build flag works on Linux (npm resolves correctly)
  • Verify --build flag works on Windows (npm.cmd resolves correctly)
  • Verify --uidev flag works on both platforms

🤖 Generated with Claude Code

On Windows, npm is a batch script (npm.cmd) that subprocess cannot
find without shell=True. Instead of adding shell=True (security
concern per Bandit B602), use shutil.which() to resolve the full
path to npm on any platform.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves cross-platform support for Caldera’s server-side UI build/dev flags by resolving npm via shutil.which() instead of relying on shell=True, targeting Windows compatibility and avoiding Bandit B602 concerns.

Changes:

  • Add _resolve_npm() helper to locate npm and provide a clearer error when missing.
  • Update Vue dev server startup to use the resolved npm path.
  • Update --uidev / --build npm subprocess calls to use the resolved npm path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server.py
Comment on lines +53 to +59
npm = shutil.which("npm")
if npm is None:
raise FileNotFoundError(
"npm is not installed or not on PATH. "
"Install Node.js (https://nodejs.org/) and ensure npm is available."
)
return npm
@sonarqubecloud
Copy link
Copy Markdown

1 similar comment
@sonarqubecloud
Copy link
Copy Markdown

…which

On Windows, shutil.which("npm") resolves to npm.cmd, and .cmd files
cannot be executed directly by subprocess without shell=True. Add
shell=(sys.platform == "win32") to subprocess.run calls and use
create_subprocess_shell on Windows for the async dev server call.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves cross-platform support for invoking npm from server.py (notably for Windows) when using the --build and --uidev flags, aiming to avoid shell=True by resolving the npm executable path first.

Changes:

  • Added _resolve_npm() helper that uses shutil.which("npm") and raises a clear error if npm is missing.
  • Updated Vue dev-server startup to use resolved npm and a Windows-specific subprocess path.
  • Updated --build / --uidev npm invocations to use the resolved npm executable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server.py
Comment on lines +210 to +213
# be executed directly by create_subprocess_exec, so use shell.
cmd = subprocess.list2cmdline([npm, "run", "dev"])
proc = await asyncio.create_subprocess_shell(
cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=MAGMA_PATH,
Comment thread server.py
Comment on lines +344 to +345
subprocess.run([npm, "run", "build"], cwd=MAGMA_PATH, check=True,
shell=(sys.platform == "win32"))
Comment thread server.py
Comment on lines +47 to +51
"""Resolve the full path to the npm executable.

On Windows, ``npm`` is a batch script (``npm.cmd``) that
``subprocess`` cannot find without ``shell=True``. Using
``shutil.which`` resolves the correct path on every platform.
Comment thread server.py
Comment on lines +360 to +363
subprocess.run([npm, "install"], cwd=MAGMA_PATH, check=True,
shell=(sys.platform == "win32"))
subprocess.run([npm, "run", "build"], cwd=MAGMA_PATH, check=True,
shell=(sys.platform == "win32"))
@uruwhy
Copy link
Copy Markdown
Contributor

uruwhy commented Apr 13, 2026

we don't officially support running caldera on windows - we still want to add this?

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.

3 participants