diff --git a/backend/apps/outputs/runtime.py b/backend/apps/outputs/runtime.py index d65173b6..5d449f07 100644 --- a/backend/apps/outputs/runtime.py +++ b/backend/apps/outputs/runtime.py @@ -376,6 +376,8 @@ class AppRuntime: env = {k: v for k, v in os.environ.items() if k != "OPENSWARM_AUTH_TOKEN"} # Hand the workspace's backend/run.sh the exact interpreter we're running on. In the packaged build that's the bundled standalone Python, so a fresh machine with no system `python3` still works; in dev it's whatever launched uvicorn. OPENSWARM_NODE_PATH already rides in via os.environ (set by the Electron shell) for run.sh's Node resolution. env["OPENSWARM_PYTHON"] = sys.executable + # Force npm to skip dependency lifecycle scripts for every install run.sh triggers. An imported app's package.json is untrusted (it brings its own run.sh, so we can't gate the flag there); a malicious dep's postinstall would otherwise run arbitrary code on the host the moment its preview boots. Vite/esbuild get their platform binary via optionalDependencies, not a script, so this doesn't break the build. + env["npm_config_ignore_scripts"] = "true" return env async def stop(self) -> None: diff --git a/backend/apps/outputs/view_builder_templates.py b/backend/apps/outputs/view_builder_templates.py index a85dc88c..8df78412 100644 --- a/backend/apps/outputs/view_builder_templates.py +++ b/backend/apps/outputs/view_builder_templates.py @@ -303,7 +303,7 @@ def ensure_warm_cache() -> str | None: tmpl_pkg = os.path.join(WEBAPP_TEMPLATE_DIR, "frontend", "package.json") tmpl_lock = os.path.join(WEBAPP_TEMPLATE_DIR, "frontend", "package-lock.json") shutil.copyfile(tmpl_pkg, os.path.join(cache_dir, "package.json")) - base_flags = ["--prefer-offline", "--no-audit", "--no-fund", "--loglevel=error"] + base_flags = ["--prefer-offline", "--no-audit", "--no-fund", "--loglevel=error", "--ignore-scripts"] npm = p_resolve_npm() if npm is None: logger.info("webapp-template: no npm available; skipping warm cache (workspace will install on first run)")