fix: restore bundled plugin dep install by default after npm pack#70650
fix: restore bundled plugin dep install by default after npm pack#70650EronFan wants to merge 12 commits into
Conversation
Root cause: cleanupBundleMcpOnRunEnd was gated behind a flag, causing MCP stdio servers spawned per session to accumulate unboundedly when the flag was false or unset. Every session created orphaned MCP processes consuming RAM (reported 2.4GB from a single context7-mcp instance). Fix: always call disposeSessionMcpRuntime() in the run finally block, removing the conditional cleanupBundleMcpOnRunEnd flag and making session cleanup unconditional. Also removes the now-unnecessary flag from RunEmbeddedPiAgentParams and cleans up all test references. Affected files: - run.ts: remove flag guard, always call disposeSessionMcpRuntime - params.ts: remove cleanupBundleMcpOnRunEnd from RunEmbeddedPiAgentParams - attempt-execution.ts / types.ts / agent-via-gateway.ts: remove flag - e2e.test.ts / agent.test.ts: remove test references to the flag Fixes openclaw#69465
…nt config Commit caab5a6 removed the flag from RunEmbeddedPiAgentParams but missed cleaning up agent.test.ts, agent-via-gateway.test.ts, and live.test.ts, causing TS2353 at build time. Also add passWithNoTests to vitest.agents.config.ts so it exits cleanly when only .live.test.ts files are staged (they are included by the glob but then excluded by the shared **/*.live.test.ts filter, leaving no files).
Fix openclaw#70234 - Codex ACP subagents fail with ACP_TURN_FAILED because spawnAcpDirect() accepted model/thinking params but never forwarded them into the gateway agent request, causing wrong default runtime. Also add regression tests for both tool layer and gateway call layer. Targeted tests: 2 files, 58 tests passed.
…ent restart storm Fix openclaw#70232 - Bonjour mDNS crash causes restart storm on VPS/cloud. When @homebridge/ciao surfaces CIAO_PROBING_CANCELLED on mDNS-broken networks, the advertiser/watchdog would keep retrying indefinitely. Now disables the advertiser, clears the watchdog, and shuts down the current ciao cycle when a ciao cancellation is seen. Add regression tests for both unhandled rejection and watchdog re-advertise paths with CIAO PROBING CANCELLED.
Regressed by commit 8a43328 which added shouldEagerInstallBundledPluginDeps() guard — bundled plugin deps (feishu/node-sdk, whatsapp/baileys, matrix libs) are now plugin-local (f6360da) but the eager-install gate disabled them by default for npm pack installs. The postinstall now always installs missing plugin runtime deps for packaged installs (non-source-checkout), matching the original behavior before the regression. Source checkouts still prune bundled plugin node_modules via the existing isSourceCheckout() branch.
Greptile SummaryThis PR bundles several independent bug fixes: (1) the headline fix restores bundled plugin dep installation for packaged (
Confidence Score: 5/5Safe to merge; all remaining findings are P2 or lower and the fixes are well-tested with explicit regression tests. The core postinstall fix is correct — applyBundledPluginRuntimeHotfixes is still called (either in the missingSpecs.length === 0 early-return path or unconditionally after the npm install block), so no hotfix logic is lost. The bonjour null-safety is handled (stopCycle accepts BonjourCycle | null and guards with if (!cycle) return). The cleanupBundleMcpOnRunEnd removal is straightforward. The only notable side-effect is the DM session key migration, which is intentional and documented. No files require special attention — all 31 changed files look correct. Reviews (1): Last reviewed commit: "fix: restore bundled plugin dep install ..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6f1b6f405
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| } | ||
|
|
||
| export default createAgentsVitestConfig(); | ||
| export default createAgentsVitestConfig({ passWithNoTests: true }); |
There was a problem hiding this comment.
Pass passWithNoTests via options, not env override
createAgentsVitestConfig interprets its argument as an env map, so createAgentsVitestConfig({ passWithNoTests: true }) replaces process.env with a one-key object instead of setting Vitest options. This means createScopedVitestConfig can no longer read env-scoped includes (e.g. OPENCLAW_VITEST_INCLUDE_FILE in sharded runs), so the agents project can execute the wrong test scope, and passWithNoTests still isn't applied because it never reaches the options object.
Useful? React with 👍 / 👎.
🔒 Aisle Security AnalysisWe found 3 potential security issue(s) in this PR:
1. 🟠 Install-time code execution risk: postinstall runs `npm install` for plugin deps with lifecycle scripts enabled
Description
Security impact:
Vulnerable code (install-time execution path): const result = spawn(npmRunner.command, npmRunner.args, {
cwd: packageRoot,
encoding: "utf8",
env: npmRunner.env ?? nestedEnv,
stdio: "pipe",
shell: npmRunner.shell,
windowsVerbatimArguments: npmRunner.windowsVerbatimArguments,
});and dependency specs are sourced from plugin manifests: const packageJson = readJsonFile(packageJsonPath);
for (const [name, version] of Object.entries(collectRuntimeDeps(packageJson))) {
deps.set(name, { name, version, ... });
}RecommendationAvoid executing third-party lifecycle scripts during install-time dependency remediation. Preferred: disable scripts and only install from controlled, integrity-checked sources. Example hardening: const nestedEnv = createNestedNpmInstallEnv(env);
// Disable lifecycle scripts
nestedEnv.npm_config_ignore_scripts = "true";
const npmRunner = resolveNpmRunner({
env: nestedEnv,
...,
npmArgs: [
"install",
"--omit=dev",
"--no-save",
"--package-lock=false",
"--legacy-peer-deps",
"--ignore-scripts",
...missingSpecs,
],
});Additional mitigations (defense in depth):
2. 🟡 Missing authorization for user-controlled `thinking` override in gateway agent handler
DescriptionThe gateway RPC handler for
Impact:
Vulnerable code: const allowModelOverride = resolveAllowModelOverrideFromClient(client);
const requestedModelOverride = Boolean(request.provider || request.model);
if (requestedModelOverride && !allowModelOverride) { /* reject */ }
// ... later
thinking: request.thinking,RecommendationEnforce authorization and validation for Suggested approach:
Example: const allowThinkingOverride = resolveSenderIsOwnerFromClient(client) || client?.internal?.allowThinkingOverride === true;
if (request.thinking && !allowThinkingOverride) {
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST,
"thinking override is not authorized for this caller."));
return;
}
const thinking = request.thinking ? normalizeThinkLevel(request.thinking) : undefined;
if (request.thinking && !thinking) {
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST,
"invalid thinking level"));
return;
}
// ...
thinking,3. 🔵 Unvalidated OpenRouter canonical_slug aliasing allows cache poisoning and unbounded cache growth
Description
This introduces two issues when the OpenRouter catalog response is malicious/compromised (or provided by an attacker-controlled proxy via
Vulnerable code: const parsed = parseModel(model);
map.set(model.id, parsed);
if (model.canonical_slug && model.canonical_slug !== model.id) {
map.set(model.canonical_slug, parsed);
}RecommendationTreat
Example: function isSafeAlias(alias: unknown): alias is string {
return (
typeof alias === "string" &&
alias.length > 0 &&
alias.length <= 128 &&
/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(alias)
);
}
// ...
map.set(model.id, parsed);
if (isSafeAlias(model.canonical_slug) && model.canonical_slug !== model.id) {
if (!map.has(model.canonical_slug)) {
map.set(model.canonical_slug, parsed);
}
}Analyzed PR: #70650 at commit Last updated on: 2026-04-23T15:35:06Z |
|
Closing this for now. The bundled-deps regression it targets is fixed in Main concerns:
If any of the unrelated fixes in this PR are still needed, please split them into focused PRs with one behavior change each. If there is a real |
Bug
After upgrading via
npm pack+ global install, plugin runtime dependencies (e.g.@larksuiteoapi/node-sdkfor Feishu,@whiskeysockets/baileysfor WhatsApp) are missing. Onboarding fails.Root Cause
8a4332864baddedshouldEagerInstallBundledPluginDeps()guard returning false by default.f6360da116moved plugin deps to plugin-local. Result:npm packtarball excludes pluginnode_modulesand postinstall skips installing them.Fix
Remove the
shouldEagerInstallBundledPluginDeps()gate. Packaged installs now always run the bundled plugin dep install step. Updated regression test (24 tests pass).