mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 11:04:06 +00:00
fix(agent-core): cap shell exec timeouts
This commit is contained in:
21
packages/agent-core/src/harness/env/nodejs.test.ts
vendored
Normal file
21
packages/agent-core/src/harness/env/nodejs.test.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveExecTimeoutMs } from "./nodejs.js";
|
||||
|
||||
describe("NodeExecutionEnv timeout helpers", () => {
|
||||
it("converts positive timeout seconds to milliseconds", () => {
|
||||
expect(resolveExecTimeoutMs(1)).toBe(1_000);
|
||||
expect(resolveExecTimeoutMs(1.5)).toBe(1_500);
|
||||
expect(resolveExecTimeoutMs(0.0005)).toBe(1);
|
||||
});
|
||||
|
||||
it("caps oversized timeout seconds to a timer-safe delay", () => {
|
||||
expect(resolveExecTimeoutMs(Number.MAX_SAFE_INTEGER)).toBe(2_147_000_000);
|
||||
});
|
||||
|
||||
it("ignores absent, invalid, or non-positive timeout seconds", () => {
|
||||
expect(resolveExecTimeoutMs(undefined)).toBeUndefined();
|
||||
expect(resolveExecTimeoutMs(Number.NaN)).toBeUndefined();
|
||||
expect(resolveExecTimeoutMs(0)).toBeUndefined();
|
||||
expect(resolveExecTimeoutMs(-1)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
26
packages/agent-core/src/harness/env/nodejs.ts
vendored
26
packages/agent-core/src/harness/env/nodejs.ts
vendored
@@ -29,10 +29,27 @@ import {
|
||||
} from "../types.js";
|
||||
import { killProcessTree } from "./kill-tree.js";
|
||||
|
||||
const MAX_TIMER_TIMEOUT_MS = 2_147_000_000;
|
||||
|
||||
function resolvePath(cwd: string, path: string): string {
|
||||
return isAbsolute(path) ? path : resolve(cwd, path);
|
||||
}
|
||||
|
||||
export function resolveExecTimeoutMs(timeoutSeconds: unknown): number | undefined {
|
||||
if (
|
||||
typeof timeoutSeconds !== "number" ||
|
||||
!Number.isFinite(timeoutSeconds) ||
|
||||
timeoutSeconds <= 0
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const milliseconds = Math.floor(timeoutSeconds * 1000);
|
||||
if (!Number.isFinite(milliseconds) || milliseconds <= 0) {
|
||||
return 1;
|
||||
}
|
||||
return Math.min(milliseconds, MAX_TIMER_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
function fileKindFromStats(stats: {
|
||||
isFile(): boolean;
|
||||
isDirectory(): boolean;
|
||||
@@ -309,15 +326,16 @@ export class NodeExecutionEnv implements ExecutionEnv {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeoutMs = resolveExecTimeoutMs(options?.timeout);
|
||||
timeoutId =
|
||||
typeof options?.timeout === "number"
|
||||
? setTimeout(() => {
|
||||
timeoutMs === undefined
|
||||
? undefined
|
||||
: setTimeout(() => {
|
||||
timedOut = true;
|
||||
if (child?.pid) {
|
||||
killProcessTree(child.pid, { force: true });
|
||||
}
|
||||
}, options.timeout * 1000)
|
||||
: undefined;
|
||||
}, timeoutMs);
|
||||
|
||||
if (options?.abortSignal) {
|
||||
if (options.abortSignal.aborted) {
|
||||
|
||||
Reference in New Issue
Block a user